diff options
Diffstat (limited to 'indra')
55 files changed, 2754 insertions, 2654 deletions
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 <string>
-
-#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 <string> + +#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<LLImageRaw>& 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<LLImageRaw>& 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<LLImageRaw>& 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<LLImageRaw>& 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<LLImageRaw>& raw, S32 discard = -1);
- BOOL requestDecodedAuxData(LLPointer<LLImageRaw>& 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<LLImageFormatted> mFormattedImage;
- LLPointer<LLImageRaw> mDecodedImage;
- S32 mDecodedType;
- S32 mDiscardLevel;
-
-private:
- U32 mPriority;
- LLPointer<LLResponder> 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<LLImageRaw>& raw, S32 discard = -1); + BOOL requestDecodedAuxData(LLPointer<LLImageRaw>& 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<LLImageFormatted> mFormattedImage; + LLPointer<LLImageRaw> mDecodedImage; + S32 mDecodedType; + S32 mDiscardLevel; + +private: + U32 mPriority; + LLPointer<LLResponder> 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 T> class LLOctreeState; template <class T> 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<const LLUICtrl* const>(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<SortByTabOrder>
-{
- /*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<const LLUICtrl* const>(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<SortByTabOrder> +{ + /*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 <list>
-
-#include "llmemory.h"
-
-class LLView;
-
-typedef std::list<LLView *> viewList_t;
-typedef std::pair<BOOL, BOOL> 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<LLNoLeavesFilter>
-{
- /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
-};
-class LLVisibleFilter : public LLQueryFilter, public LLSingleton<LLVisibleFilter>
-{
- /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
-};
-class LLEnabledFilter : public LLQueryFilter, public LLSingleton<LLEnabledFilter>
-{
- /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
-};
-class LLTabStopFilter : public LLQueryFilter, public LLSingleton<LLTabStopFilter>
-{
- /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
-};
-
-// Algorithm for flattening
-class LLViewQuery
-{
-public:
- typedef std::list<const LLQueryFilter*> 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 <list> + +#include "llmemory.h" + +class LLView; + +typedef std::list<LLView *> viewList_t; +typedef std::pair<BOOL, BOOL> 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<LLNoLeavesFilter> +{ + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; +}; +class LLVisibleFilter : public LLQueryFilter, public LLSingleton<LLVisibleFilter> +{ + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; +}; +class LLEnabledFilter : public LLQueryFilter, public LLSingleton<LLEnabledFilter> +{ + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; +}; +class LLTabStopFilter : public LLQueryFilter, public LLSingleton<LLTabStopFilter> +{ + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; +}; + +// Algorithm for flattening +class LLViewQuery +{ +public: + typedef std::list<const LLQueryFilter*> 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<std::pair<F32,LLPointer<LLDrawable> > > 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<LLObjectSelection> 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<LLObjectSelection> 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> 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;t<sizeof(enableNames)/sizeof(char*);t++) + for(size_t t=0; t<sizeof(enableNames)/sizeof(char*); ++t) { childSetEnabled(enableNames[t],false); } @@ -225,7 +225,7 @@ void LLFloaterProperties::refresh() "EveryoneMaskDebug", "NextMaskDebug" }; - for(int t=0;t<sizeof(hideNames)/sizeof(char*);t++) + for(size_t t=0; t<sizeof(hideNames)/sizeof(char*); ++t) { childSetVisible(hideNames[t],false); } diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 34eb841568..63b1734642 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -245,7 +245,7 @@ BOOL LLFloaterTools::postBuild() &LLToolPlacerPanel::sTriangleTorus, &LLToolPlacerPanel::sTree, &LLToolPlacerPanel::sGrass}; - for(int t=0;t<sizeof(toolNames)/sizeof(toolNames[0]);t++) + for(size_t t=0; t<sizeof(toolNames)/sizeof(toolNames[0]); ++t) { LLButton *found = LLViewerUICtrlFactory::getButtonByName(this,toolNames[t]); if(found) diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 33a675b59e..00108650ef 100644 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -843,7 +843,7 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data) } } - if (group_datap->mMembers.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;t<mSkillsCount;t++) + for(S32 tt=0; tt < mSkillsCount; ++tt) { //Find the Skills checkboxes and save off thier controls - LLString ctlname = llformat("schk%d",t); - mSkillsCheck[t] = LLUICtrlFactory::getCheckBoxByName(this,ctlname); + LLString ctlname = llformat("schk%d",tt); + mSkillsCheck[tt] = LLUICtrlFactory::getCheckBoxByName(this,ctlname); } mWantToEdit = LLUICtrlFactory::getLineEditorByName(this,"want_to_edit"); diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 2c6cbb9c08..9adc737aab 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -83,16 +83,17 @@ LLPanelClassified::LLPanelClassified(BOOL in_finder) mDataRequested(FALSE), mEnableCommit(FALSE), mPaidFor(FALSE), - mParcelID(), mPosGlobal(), mSnapshotCtrl(NULL), mNameEditor(NULL), - mLocationEditor(NULL), mDescEditor(NULL), + mLocationEditor(NULL), + mCategoryCombo(NULL), + mUpdateBtn(NULL), mTeleportBtn(NULL), mMapBtn(NULL), - //mLandmarkBtn(NULL), - //mEnabledCheck(NULL), + mProfileBtn(NULL), + mInfoText(NULL), mMatureCheck(NULL), mAutoRenewCheck(NULL), mSetBtn(NULL), diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index 9ad5855b8e..121dc4c67e 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -132,8 +132,8 @@ LLPanelGroup::LLPanelGroup(const std::string& filename, mCurrentTab( NULL ), mRequestedTab( NULL ), mTabContainer( NULL ), - mForceClose( FALSE ), mIgnoreTransition( FALSE ), + mForceClose( FALSE ), mInitialTab(initial_tab_selected), mAllowEdit( TRUE ), mShowingNotifyDialog( FALSE ) diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 0e295df94a..bda962ca56 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1101,7 +1101,10 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() check->setCommitCallback(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<LLUUID>::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<LLSelectNode*>(), 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<LLDrawable>* 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<LLTextureCache::Responder> 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<handle_t>::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_data*, lru_data::Compare> lru_set_t;
- lru_set_t lru;
- for (S32 i=0; i<num_entries; i++)
- {
- if (entries[i].mSize >= 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<LLUUID, S32> entry_idx_map;
- S64 total_size = 0;
- for (S32 idx=0; idx<num_entries; idx++)
- {
- const LLUUID& id = entries[idx].mID;
-// llinfos << "Entry: " << id << " Size: " << entries[i].mSize << " Time: " << entries[i].mTime << llendl;
- std::map<LLUUID, S32>::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<num_entries; idx++)
- {
- if (entries[idx].mSize == 0)
- {
- continue;
- }
- bool purge_entry = false;
- std::string filename = getTextureFileName(entries[idx].mID);
- if (total_size >= 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; idx<num_entries; idx++)
- {
- mTexturesSizeMap[entries[idx].mID] = entries[idx].mSize;
- mTexturesSizeTotal += entries[idx].mSize;
- }
- llassert(mTexturesSizeTotal == total_size);
-
- delete[] entries;
-
- llinfos << "TEXTURE CACHE:"
- << " PURGED: " << purge_count
- << " ENTRIES: " << num_entries
- << " CACHE SIZE: " << total_size / 1024*1024 << " MB"
- << llendl;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-// call lockWorkers() first!
-LLTextureCacheWorker* LLTextureCache::getReader(handle_t handle)
-{
- LLTextureCacheWorker* res = NULL;
- handle_map_t::iterator iter = mReaders.find(handle);
- if (iter != mReaders.end())
- {
- res = iter->second;
- }
- 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<LLTextureCache::Responder> 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<handle_t>::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_data*, lru_data::Compare> lru_set_t; + lru_set_t lru; + for (S32 i=0; i<num_entries; i++) + { + if (entries[i].mSize >= 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<LLUUID, S32> entry_idx_map; + S64 total_size = 0; + for (S32 idx=0; idx<num_entries; idx++) + { + const LLUUID& id = entries[idx].mID; +// llinfos << "Entry: " << id << " Size: " << entries[i].mSize << " Time: " << entries[i].mTime << llendl; + std::map<LLUUID, S32>::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<num_entries; idx++) + { + if (entries[idx].mSize == 0) + { + continue; + } + bool purge_entry = false; + std::string filename = getTextureFileName(entries[idx].mID); + if (total_size >= 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; idx<num_entries; idx++) + { + mTexturesSizeMap[entries[idx].mID] = entries[idx].mSize; + mTexturesSizeTotal += entries[idx].mSize; + } + llassert(mTexturesSizeTotal == total_size); + + delete[] entries; + + llinfos << "TEXTURE CACHE:" + << " PURGED: " << purge_count + << " ENTRIES: " << num_entries + << " CACHE SIZE: " << total_size / 1024*1024 << " MB" + << llendl; +} + +////////////////////////////////////////////////////////////////////////////// + +// call lockWorkers() first! +LLTextureCacheWorker* LLTextureCache::getReader(handle_t handle) +{ + LLTextureCacheWorker* res = NULL; + handle_map_t::iterator iter = mReaders.find(handle); + if (iter != mReaders.end()) + { + res = iter->second; + } + 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<LLImageFormatted> 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_t, LLTextureCacheWorker*> handle_map_t;
- handle_map_t mReaders;
- handle_map_t mWriters;
- std::vector<handle_t> 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<S32,LLUUID> index_map_t;
- index_map_t mLRU; // index, id; stored as a map for fast removal
- typedef std::map<LLUUID,S32> id_map_t;
- id_map_t mHeaderIDMap;
-
- // BODIES (TEXTURES minus headers)
- std::string mTexturesDirName;
- std::string mTexturesDirEntriesFileName;
- typedef std::map<LLUUID,S32> size_map_t;
- size_map_t mTexturesSizeMap;
- S64 mTexturesSizeTotal;
- LLAtomic32<BOOL> 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<LLImageFormatted> 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_t, LLTextureCacheWorker*> handle_map_t; + handle_map_t mReaders; + handle_map_t mWriters; + std::vector<handle_t> 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<S32,LLUUID> index_map_t; + index_map_t mLRU; // index, id; stored as a map for fast removal + typedef std::map<LLUUID,S32> id_map_t; + id_map_t mHeaderIDMap; + + // BODIES (TEXTURES minus headers) + std::string mTexturesDirName; + std::string mTexturesDirEntriesFileName; + typedef std::map<LLUUID,S32> size_map_t; + size_map_t mTexturesSizeMap; + S64 mTexturesSizeTotal; + LLAtomic32<BOOL> 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<LLViewerImage> mAlphaSizzleImagep; |