diff options
Diffstat (limited to 'indra/llimage/llimageworker.cpp')
-rw-r--r-- | indra/llimage/llimageworker.cpp | 444 |
1 files changed, 225 insertions, 219 deletions
diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index f97d991ca6..62934ccbe1 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -1,219 +1,225 @@ -/** - * @file llimageworker.cpp - * @brief Base class for images. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llimageworker.h" -#include "llimagedxt.h" -#include "threadpool.h" - -/*--------------------------------------------------------------------------*/ -class ImageRequest -{ -public: - ImageRequest(const LLPointer<LLImageFormatted>& image, - S32 discard, - bool needs_aux, - const LLPointer<LLImageDecodeThread::Responder>& responder, - U32 request_id); - virtual ~ImageRequest(); - - /*virtual*/ bool processRequest(); - /*virtual*/ void finishRequest(bool completed); - -private: - // LLPointers stored in ImageRequest MUST be LLPointer instances rather - // than references: we need to increment the refcount when storing these. - // input - LLPointer<LLImageFormatted> mFormattedImage; - S32 mDiscardLevel; - U32 mRequestId; - bool mNeedsAux; - // output - LLPointer<LLImageRaw> mDecodedImageRaw; - LLPointer<LLImageRaw> mDecodedImageAux; - bool mDecodedRaw; - bool mDecodedAux; - LLPointer<LLImageDecodeThread::Responder> mResponder; -}; - - -//---------------------------------------------------------------------------- - -// MAIN THREAD -LLImageDecodeThread::LLImageDecodeThread(bool /*threaded*/) - : mDecodeCount(0) -{ - mThreadPool.reset(new LL::ThreadPool("ImageDecode", 8)); - mThreadPool->start(); -} - -//virtual -LLImageDecodeThread::~LLImageDecodeThread() -{} - -// MAIN THREAD -// virtual -size_t LLImageDecodeThread::update(F32 max_time_ms) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - return getPending(); -} - -size_t LLImageDecodeThread::getPending() -{ - return mThreadPool->getQueue().size(); -} - -LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage( - const LLPointer<LLImageFormatted>& image, - S32 discard, - bool needs_aux, - const LLPointer<LLImageDecodeThread::Responder>& responder) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - - U32 decode_id = ++mDecodeCount; - // Instantiate the ImageRequest right in the lambda, why not? - bool posted = mThreadPool->getQueue().post( - [req = ImageRequest(image, discard, needs_aux, responder, decode_id)] - () mutable - { - auto done = req.processRequest(); - req.finishRequest(done); - }); - if (! posted) - { - LL_DEBUGS() << "Tried to start decoding on shutdown" << LL_ENDL; - return 0; - } - - return decode_id; -} - -void LLImageDecodeThread::shutdown() -{ - mThreadPool->close(); -} - -LLImageDecodeThread::Responder::~Responder() -{ -} - -//---------------------------------------------------------------------------- - -ImageRequest::ImageRequest(const LLPointer<LLImageFormatted>& image, - S32 discard, - bool needs_aux, - const LLPointer<LLImageDecodeThread::Responder>& responder, - U32 request_id) - : mFormattedImage(image), - mDiscardLevel(discard), - mNeedsAux(needs_aux), - mDecodedRaw(false), - mDecodedAux(false), - mResponder(responder), - mRequestId(request_id) -{ -} - -ImageRequest::~ImageRequest() -{ - mDecodedImageRaw = NULL; - mDecodedImageAux = NULL; - mFormattedImage = NULL; -} - -//---------------------------------------------------------------------------- - - -// Returns true when done, whether or not decode was successful. -bool ImageRequest::processRequest() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - - if (mFormattedImage.isNull()) - return true; - - const F32 decode_time_slice = 0.f; //disable time slicing - bool done = true; - - LLImageDataLock lockFormatted(mFormattedImage); - LLImageDataLock lockDecodedRaw(mDecodedImageRaw); - LLImageDataLock lockDecodedAux(mDecodedImageAux); - - if (!mDecodedRaw) - { - // Decode primary channels - if (mDecodedImageRaw.isNull()) - { - // 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); - // some decoders are removing data when task is complete and there were errors - mDecodedRaw = done && mDecodedImageRaw->getData(); - } - if (done && mNeedsAux && !mDecodedAux) - { - // Decode aux channel - if (!mDecodedImageAux) - { - mDecodedImageAux = new LLImageRaw(mFormattedImage->getWidth(), - mFormattedImage->getHeight(), - 1); - } - done = mFormattedImage->decodeChannels(mDecodedImageAux, decode_time_slice, 4, 4); - mDecodedAux = done && mDecodedImageAux->getData(); - } - - return done; -} - -void ImageRequest::finishRequest(bool completed) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if (mResponder.notNull()) - { - bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux); - mResponder->completed(success, mDecodedImageRaw, mDecodedImageAux, mRequestId); - } - // Will automatically be deleted -} +/**
+ * @file llimageworker.cpp
+ * @brief Base class for images.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llimageworker.h"
+#include "llimagedxt.h"
+#include "threadpool.h"
+
+/*--------------------------------------------------------------------------*/
+class ImageRequest
+{
+public:
+ ImageRequest(const LLPointer<LLImageFormatted>& image,
+ S32 discard,
+ bool needs_aux,
+ const LLPointer<LLImageDecodeThread::Responder>& responder,
+ U32 request_id);
+ virtual ~ImageRequest();
+
+ /*virtual*/ bool processRequest();
+ /*virtual*/ void finishRequest(bool completed);
+
+private:
+ // LLPointers stored in ImageRequest MUST be LLPointer instances rather
+ // than references: we need to increment the refcount when storing these.
+ // input
+ LLPointer<LLImageFormatted> mFormattedImage;
+ S32 mDiscardLevel;
+ U32 mRequestId;
+ bool mNeedsAux;
+ // output
+ LLPointer<LLImageRaw> mDecodedImageRaw;
+ LLPointer<LLImageRaw> mDecodedImageAux;
+ bool mDecodedRaw;
+ bool mDecodedAux;
+ LLPointer<LLImageDecodeThread::Responder> mResponder;
+ std::string mErrorString;};
+
+
+//----------------------------------------------------------------------------
+
+// MAIN THREAD
+LLImageDecodeThread::LLImageDecodeThread(bool /*threaded*/)
+ : mDecodeCount(0)
+{
+ mThreadPool.reset(new LL::ThreadPool("ImageDecode", 8));
+ mThreadPool->start();
+}
+
+//virtual
+LLImageDecodeThread::~LLImageDecodeThread()
+{}
+
+// MAIN THREAD
+// virtual
+size_t LLImageDecodeThread::update(F32 max_time_ms)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+ return getPending();
+}
+
+size_t LLImageDecodeThread::getPending()
+{
+ return mThreadPool->getQueue().size();
+}
+
+LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(
+ const LLPointer<LLImageFormatted>& image,
+ S32 discard,
+ bool needs_aux,
+ const LLPointer<LLImageDecodeThread::Responder>& responder)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+
+ U32 decode_id = ++mDecodeCount;
+ // Instantiate the ImageRequest right in the lambda, why not?
+ bool posted = mThreadPool->getQueue().post(
+ [req = ImageRequest(image, discard, needs_aux, responder, decode_id)]
+ () mutable
+ {
+ auto done = req.processRequest();
+ req.finishRequest(done);
+ });
+ if (! posted)
+ {
+ LL_DEBUGS() << "Tried to start decoding on shutdown" << LL_ENDL;
+ return 0;
+ }
+
+ return decode_id;
+}
+
+void LLImageDecodeThread::shutdown()
+{
+ mThreadPool->close();
+}
+
+LLImageDecodeThread::Responder::~Responder()
+{
+}
+
+//----------------------------------------------------------------------------
+
+ImageRequest::ImageRequest(const LLPointer<LLImageFormatted>& image,
+ S32 discard,
+ bool needs_aux,
+ const LLPointer<LLImageDecodeThread::Responder>& responder,
+ U32 request_id)
+ : mFormattedImage(image),
+ mDiscardLevel(discard),
+ mNeedsAux(needs_aux),
+ mDecodedRaw(false),
+ mDecodedAux(false),
+ mResponder(responder),
+ mRequestId(request_id)
+{
+}
+
+ImageRequest::~ImageRequest()
+{
+ mDecodedImageRaw = NULL;
+ mDecodedImageAux = NULL;
+ mFormattedImage = NULL;
+}
+
+//----------------------------------------------------------------------------
+
+
+// Returns true when done, whether or not decode was successful.
+bool ImageRequest::processRequest()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+
+ if (mFormattedImage.isNull())
+ return true;
+
+ const F32 decode_time_slice = 0.f; //disable time slicing
+ bool done = true;
+
+ LLImageDataLock lockFormatted(mFormattedImage);
+ LLImageDataLock lockDecodedRaw(mDecodedImageRaw);
+ LLImageDataLock lockDecodedAux(mDecodedImageAux);
+
+ if (!mDecodedRaw)
+ {
+ // Decode primary channels
+ if (mDecodedImageRaw.isNull())
+ {
+ // parse formatted header
+ if (!mFormattedImage->updateData())
+ {
+ return true; // done (failed)
+ }
+ if ((mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents()) == 0)
+ {
+ 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);
+ // some decoders are removing data when task is complete and there were errors
+ mDecodedRaw = done && mDecodedImageRaw->getData();
+
+ // Pick up errors from decoding
+ mErrorString = LLImage::getLastThreadError();
+ }
+ if (done && mNeedsAux && !mDecodedAux && mFormattedImage.notNull())
+ {
+ // Decode aux channel
+ if (!mDecodedImageAux)
+ {
+ mDecodedImageAux = new LLImageRaw(mFormattedImage->getWidth(),
+ mFormattedImage->getHeight(),
+ 1);
+ }
+ done = mFormattedImage->decodeChannels(mDecodedImageAux, decode_time_slice, 4, 4);
+ mDecodedAux = done && mDecodedImageAux->getData();
+
+ // Pick up errors from decoding
+ mErrorString = LLImage::getLastThreadError();
+ }
+
+ return done;
+}
+
+void ImageRequest::finishRequest(bool completed)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+ if (mResponder.notNull())
+ {
+ bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux);
+ mResponder->completed(success, mErrorString, mDecodedImageRaw, mDecodedImageAux, mRequestId);
+ }
+ // Will automatically be deleted
+}
|