From e6247fbe78c4d3dacb74f3b2359aba2b6538133b Mon Sep 17 00:00:00 2001 From: Jacek Antonelli Date: Tue, 9 Feb 2010 21:11:42 -0600 Subject: Ported many texture engine changes from Snowglobe. --- linden/indra/llimage/llimage.cpp | 38 +++---- linden/indra/llimage/llimage.h | 8 +- linden/indra/llimage/llimagedxt.cpp | 19 +++- linden/indra/llimage/llimagej2c.cpp | 5 +- linden/indra/llimage/llimagejpeg.cpp | 9 +- linden/indra/llimage/llimageworker.cpp | 202 +++++++++++++++------------------ linden/indra/llimage/llimageworker.h | 97 ++++++++++------ 7 files changed, 198 insertions(+), 180 deletions(-) (limited to 'linden/indra/llimage') diff --git a/linden/indra/llimage/llimage.cpp b/linden/indra/llimage/llimage.cpp index 4b0076e..32891e7 100644 --- a/linden/indra/llimage/llimage.cpp +++ b/linden/indra/llimage/llimage.cpp @@ -55,13 +55,9 @@ std::string LLImage::sLastErrorMessage; LLMutex* LLImage::sMutex = NULL; //static -void LLImage::initClass(LLWorkerThread* workerthread) +void LLImage::initClass() { sMutex = new LLMutex(NULL); - if (workerthread) - { - LLImageWorker::initImageWorker(workerthread); - } LLImageJ2C::openDSO(); } @@ -69,7 +65,6 @@ void LLImage::initClass(LLWorkerThread* workerthread) void LLImage::cleanupClass() { LLImageJ2C::closeDSO(); - LLImageWorker::cleanupImageWorker(); delete sMutex; sMutex = NULL; } @@ -1242,25 +1237,28 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip ifs.read ((char*)buffer, length); /* Flawfinder: ignore */ ifs.close(); - image->updateData(); - - if (j2c_lowest_mip_only && codec == IMG_CODEC_J2C) + BOOL success; + + success = image->updateData(); + if (success) { - S32 width = image->getWidth(); - S32 height = image->getHeight(); - S32 discard_level = 0; - while (width > 1 && height > 1 && discard_level < MAX_DISCARD_LEVEL) + if (j2c_lowest_mip_only && codec == IMG_CODEC_J2C) { - width >>= 1; - height >>= 1; - discard_level++; + S32 width = image->getWidth(); + S32 height = image->getHeight(); + S32 discard_level = 0; + while (width > 1 && height > 1 && discard_level < MAX_DISCARD_LEVEL) + { + width >>= 1; + height >>= 1; + discard_level++; + } + ((LLImageJ2C *)((LLImageFormatted*)image))->setDiscardLevel(discard_level); } - ((LLImageJ2C *)((LLImageFormatted*)image))->setDiscardLevel(discard_level); + success = image->decode(this, 100000.0f); } - - BOOL success = image->decode(this, 100000.0f); - image = NULL; // deletes image + image = NULL; // deletes image if (!success) { deleteData(); diff --git a/linden/indra/llimage/llimage.h b/linden/indra/llimage/llimage.h index bd609b6..be2eb08 100644 --- a/linden/indra/llimage/llimage.h +++ b/linden/indra/llimage/llimage.h @@ -49,7 +49,8 @@ const S32 MAX_IMAGE_AREA = MAX_IMAGE_SIZE * MAX_IMAGE_SIZE; const S32 MAX_IMAGE_COMPONENTS = 8; const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS; -// Note! These CANNOT be changed without invalidating the viewer VFS files, I think? +// Note! These CANNOT be changed without modifying simulator code +// *TODO: change both to 1024 when SIM texture fetching is deprecated const S32 FIRST_PACKET_SIZE = 600; const S32 MAX_IMG_PACKET_SIZE = 1000; @@ -60,7 +61,6 @@ const S32 MAX_IMG_PACKET_SIZE = 1000; class LLImageFormatted; class LLImageRaw; class LLColor4U; -class LLWorkerThread; typedef enum e_image_codec { @@ -81,7 +81,7 @@ typedef enum e_image_codec class LLImage { public: - static void initClass(LLWorkerThread* workerthread); + static void initClass(); static void cleanupClass(); static const std::string& getLastError(); @@ -309,7 +309,7 @@ protected: protected: S8 mCodec; S8 mDecoding; - S8 mDecoded; + S8 mDecoded; // unused, but changing LLImage layout requires recompiling static Mac/Linux libs. 2009-01-30 JC S8 mDiscardLevel; public: diff --git a/linden/indra/llimage/llimagedxt.cpp b/linden/indra/llimage/llimagedxt.cpp index 1ce4517..0aa6840 100644 --- a/linden/indra/llimage/llimagedxt.cpp +++ b/linden/indra/llimage/llimagedxt.cpp @@ -264,6 +264,8 @@ void LLImageDXT::setFormat() // virtual BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time) { + // *TODO: Test! This has been tweaked since its intial inception, + // but we don't use it any more! llassert_always(raw_image); if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5) @@ -274,8 +276,17 @@ BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time) S32 width = getWidth(), height = getHeight(); S32 ncomponents = getComponents(); + U8* data = NULL; + if (mDiscardLevel >= 0) + { + data = getData() + getMipOffset(mDiscardLevel); + calcDiscardWidthHeight(mDiscardLevel, mFileFormat, width, height); + } + else + { + data = getData() + getMipOffset(0); + } S32 image_size = formatBytes(mFileFormat, width, height); - U8* data = getData() + getMipOffset(0); if ((!getData()) || (data + image_size > getData() + getDataSize())) { @@ -300,10 +311,8 @@ BOOL LLImageDXT::getMipData(LLPointer& raw, S32 discard) llerrs << "Request for invalid discard level" << llendl; } U8* data = getData() + getMipOffset(discard); - // I'm not sure these are the correct initial values for height and width, - // but previously they were being used uninitialized. JC - S32 width = raw->getWidth(); - S32 height = raw->getHeight(); + S32 width = 0; + S32 height = 0; calcDiscardWidthHeight(discard, mFileFormat, width, height); raw = new LLImageRaw(data, width, height, getComponents()); return TRUE; diff --git a/linden/indra/llimage/llimagej2c.cpp b/linden/indra/llimage/llimagej2c.cpp index ed58f85..1aae83e 100644 --- a/linden/indra/llimage/llimagej2c.cpp +++ b/linden/indra/llimage/llimagej2c.cpp @@ -277,6 +277,7 @@ BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time) } +// Returns TRUE to mean done, whether successful or not. BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count ) { LLMemType mt1((LLMemType::EMemType)mMemType); @@ -289,7 +290,7 @@ BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir if (!getData() || (getDataSize() < 16)) { setLastError("LLImageJ2C uninitialized"); - res = FALSE; + res = TRUE; // done } else { @@ -342,7 +343,7 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, //static S32 LLImageJ2C::calcHeaderSizeJ2C() { - return 600; //2048; // ??? hack... just needs to be >= actual header size... + return FIRST_PACKET_SIZE; // Hack. just needs to be >= actual header size... } //static diff --git a/linden/indra/llimage/llimagejpeg.cpp b/linden/indra/llimage/llimagejpeg.cpp index fa0dd3f..79ea79c 100644 --- a/linden/indra/llimage/llimagejpeg.cpp +++ b/linden/indra/llimage/llimagejpeg.cpp @@ -188,6 +188,7 @@ void LLImageJPEG::decodeTermSource (j_decompress_ptr cinfo) } +// Returns true when done, whether or not decode was successful. BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) { llassert_always(raw_image); @@ -198,7 +199,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) if (!getData() || (0 == getDataSize())) { setLastError("LLImageJPEG trying to decode an image with no data!"); - return FALSE; + return TRUE; // done } S32 row_stride = 0; @@ -226,7 +227,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) if(setjmp(sSetjmpBuffer)) { jpeg_destroy_decompress(&cinfo); - return FALSE; + return TRUE; // done } try { @@ -320,7 +321,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) catch (int) { jpeg_destroy_decompress(&cinfo); - return FALSE; + return TRUE; // done } // Check to see whether any corrupt-data warnings occurred @@ -328,7 +329,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) { // TODO: extract the warning to find out what went wrong. setLastError( "Unable to decode JPEG image."); - return FALSE; + return TRUE; // done } return TRUE; diff --git a/linden/indra/llimage/llimageworker.cpp b/linden/indra/llimage/llimageworker.cpp index 532e996..86d4151 100644 --- a/linden/indra/llimage/llimageworker.cpp +++ b/linden/indra/llimage/llimageworker.cpp @@ -37,152 +37,138 @@ //---------------------------------------------------------------------------- -//static -LLWorkerThread* LLImageWorker::sWorkerThread = NULL; -S32 LLImageWorker::sCount = 0; +// MAIN THREAD +LLImageDecodeThread::LLImageDecodeThread(bool threaded) + : LLQueuedThread("imagedecode", threaded) +{ + mCreationMutex = new LLMutex(getAPRPool()); +} -//static -void LLImageWorker::initImageWorker(LLWorkerThread* workerthread) +// MAIN THREAD +// virtual +S32 LLImageDecodeThread::update(U32 max_time_ms) { - sWorkerThread = workerthread; + LLMutexLock lock(mCreationMutex); + for (creation_list_t::iterator iter = mCreationList.begin(); + iter != mCreationList.end(); ++iter) + { + creation_info& info = *iter; + ImageRequest* req = new ImageRequest(info.handle, info.image, + info.priority, info.discard, info.needs_aux, + info.responder); + addRequest(req); + } + mCreationList.clear(); + S32 res = LLQueuedThread::update(max_time_ms); + return res; } -//static -void LLImageWorker::cleanupImageWorker() +LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image, + U32 priority, S32 discard, BOOL needs_aux, Responder* responder) +{ + LLMutexLock lock(mCreationMutex); + handle_t handle = generateHandle(); + mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder)); + return handle; +} + +// Used by unit test only +// Returns the size of the mutex guarded list as an indication of sanity +S32 LLImageDecodeThread::tut_size() +{ + LLMutexLock lock(mCreationMutex); + S32 res = mCreationList.size(); + return res; +} + +LLImageDecodeThread::Responder::~Responder() { } //---------------------------------------------------------------------------- -LLImageWorker::LLImageWorker(LLImageFormatted* image, U32 priority, - S32 discard, - LLPointer responder) - : LLWorkerClass(sWorkerThread, "Image"), +LLImageDecodeThread::ImageRequest::ImageRequest(handle_t handle, LLImageFormatted* image, + U32 priority, S32 discard, BOOL needs_aux, + LLImageDecodeThread::Responder* responder) + : LLQueuedThread::QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE), mFormattedImage(image), - mDecodedType(-1), mDiscardLevel(discard), - mPriority(priority), + mNeedsAux(needs_aux), + mDecodedRaw(FALSE), + mDecodedAux(FALSE), mResponder(responder) { - ++sCount; } -LLImageWorker::~LLImageWorker() +LLImageDecodeThread::ImageRequest::~ImageRequest() { - mDecodedImage = NULL; + mDecodedImageRaw = NULL; + mDecodedImageAux = NULL; mFormattedImage = NULL; - --sCount; } //---------------------------------------------------------------------------- -//virtual, main thread -void LLImageWorker::startWork(S32 param) -{ - llassert_always(mDecodedImage.isNull()); - mDecodedType = -1; -} -bool LLImageWorker::doWork(S32 param) +// Returns true when done, whether or not decode was successful. +bool LLImageDecodeThread::ImageRequest::processRequest() { - bool decoded = false; - if(mDecodedImage.isNull()) + const F32 decode_time_slice = .1f; + bool done = true; + if (!mDecodedRaw && mFormattedImage.notNull()) { - if (!mFormattedImage->updateData()) - { - mDecodedType = -2; // failed - return true; - } - if (mDiscardLevel >= 0) + // Decode primary channels + if (mDecodedImageRaw.isNull()) { - mFormattedImage->setDiscardLevel(mDiscardLevel); - } - if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents())) - { - decoded = true; // failed - } - else - { - mDecodedImage = new LLImageRaw(); // allow possibly smaller size set during decoding + // parse formatted header + if (!mFormattedImage->updateData()) + { + return true; // done (failed) + } + if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents())) + { + return true; // done (failed) + } + if (mDiscardLevel >= 0) + { + mFormattedImage->setDiscardLevel(mDiscardLevel); + } + mDecodedImageRaw = new LLImageRaw(mFormattedImage->getWidth(), + mFormattedImage->getHeight(), + mFormattedImage->getComponents()); } + done = mFormattedImage->decode(mDecodedImageRaw, decode_time_slice); // 1ms + mDecodedRaw = done; } - if (!decoded) + if (done && mNeedsAux && !mDecodedAux && mFormattedImage.notNull()) { - if (param == 0) - { - // Decode primary channels - decoded = mFormattedImage->decode(mDecodedImage, .1f); // 1ms - } - else + // Decode aux channel + if (!mDecodedImageAux) { - // Decode aux channel - decoded = mFormattedImage->decodeChannels(mDecodedImage, .1f, param, param); // 1ms + mDecodedImageAux = new LLImageRaw(mFormattedImage->getWidth(), + mFormattedImage->getHeight(), + 1); } + done = mFormattedImage->decodeChannels(mDecodedImageAux, decode_time_slice, 4, 4); // 1ms + mDecodedAux = done; } - 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; - } + return done; } -//---------------------------------------------------------------------------- - - -BOOL LLImageWorker::requestDecodedAuxData(LLPointer& raw, S32 channel, S32 discard) +void LLImageDecodeThread::ImageRequest::finishRequest(bool completed) { - // 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) + if (mResponder.notNull()) { - 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 success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux); + mResponder->completed(success, mDecodedImageRaw, mDecodedImageAux); } + // Will automatically be deleted } -BOOL LLImageWorker::requestDecodedData(LLPointer& raw, S32 discard) +// Used by unit test only +// Checks that a responder exists for this instance so that something can happen when completion is reached +bool LLImageDecodeThread::ImageRequest::tut_isOK() { - if (mFormattedImage->getCodec() == IMG_CODEC_DXT) - { - // special case - LLImageDXT* imagedxt = (LLImageDXT*)((LLImageFormatted*)mFormattedImage); - return imagedxt->getMipData(raw, discard); - } - else - { - return requestDecodedAuxData(raw, 0, discard); - } + return mResponder.notNull(); } diff --git a/linden/indra/llimage/llimageworker.h b/linden/indra/llimage/llimageworker.h index 879fcf5..fcd3039 100644 --- a/linden/indra/llimage/llimageworker.h +++ b/linden/indra/llimage/llimageworker.h @@ -34,51 +34,74 @@ #define LL_LLIMAGEWORKER_H #include "llimage.h" -#include "llworkerthread.h" +#include "llqueuedthread.h" -class LLImageWorker : public LLWorkerClass +class LLImageDecodeThread : public LLQueuedThread { public: - static void initImageWorker(LLWorkerThread* workerthread); - static void cleanupImageWorker(); - -public: - static LLWorkerThread* getWorkerThread() { return sWorkerThread; } - - // LLWorkerThread -public: - LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard, - LLPointer responder); - ~LLImageWorker(); - - // called from WORKER THREAD, returns TRUE if done - /*virtual*/ bool doWork(S32 param); - - BOOL requestDecodedData(LLPointer& raw, S32 discard = -1); - BOOL requestDecodedAuxData(LLPointer& raw, S32 channel, S32 discard = -1); - void releaseDecodedData(); - void cancelDecode(); + class Responder : public LLThreadSafeRefCount + { + protected: + virtual ~Responder(); + public: + virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) = 0; + }; -private: - // called from MAIN THREAD - /*virtual*/ void startWork(S32 param); // called from addWork() - /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() + class ImageRequest : public LLQueuedThread::QueuedRequest + { + protected: + virtual ~ImageRequest(); // use deleteRequest() + + public: + ImageRequest(handle_t handle, LLImageFormatted* image, + U32 priority, S32 discard, BOOL needs_aux, + LLImageDecodeThread::Responder* responder); -protected: - LLPointer mFormattedImage; - LLPointer mDecodedImage; - S32 mDecodedType; - S32 mDiscardLevel; + /*virtual*/ bool processRequest(); + /*virtual*/ void finishRequest(bool completed); -private: - U32 mPriority; - LLPointer mResponder; + // Used by unit tests to check the consitency of the request instance + bool tut_isOK(); + + private: + // input + LLPointer mFormattedImage; + S32 mDiscardLevel; + BOOL mNeedsAux; + // output + LLPointer mDecodedImageRaw; + LLPointer mDecodedImageAux; + BOOL mDecodedRaw; + BOOL mDecodedAux; + LLPointer mResponder; + }; -protected: - static LLWorkerThread* sWorkerThread; - public: - static S32 sCount; + LLImageDecodeThread(bool threaded = true); + handle_t decodeImage(LLImageFormatted* image, + U32 priority, S32 discard, BOOL needs_aux, + Responder* responder); + S32 update(U32 max_time_ms); + + // Used by unit tests to check the consistency of the thread instance + S32 tut_size(); + +private: + struct creation_info + { + handle_t handle; + LLImageFormatted* image; + U32 priority; + S32 discard; + BOOL needs_aux; + LLPointer responder; + creation_info(handle_t h, LLImageFormatted* i, U32 p, S32 d, BOOL aux, Responder* r) + : handle(h), image(i), priority(p), discard(d), needs_aux(aux), responder(r) + {} + }; + typedef std::list creation_list_t; + creation_list_t mCreationList; + LLMutex* mCreationMutex; }; #endif -- cgit v1.1