From 74c8b028d42a8c5b080bb861e427f38cedd4ad7c Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Fri, 15 Dec 2023 18:26:14 +0100 Subject: SL-20743 Use LLMutex in LLImageBase for internal data thread-safety --- indra/llimage/llimageworker.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'indra/llimage/llimageworker.cpp') diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index c1ee052997..44749343e1 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -149,9 +149,18 @@ ImageRequest::~ImageRequest() 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; - if (!mDecodedRaw && mFormattedImage.notNull()) + + LLImageDataLock lockFormatted(mFormattedImage); + LLImageDataLock lockDecodedRaw(mDecodedImageRaw); + LLImageDataLock lockDecodedAux(mDecodedImageAux); + + if (!mDecodedRaw) { // Decode primary channels if (mDecodedImageRaw.isNull()) @@ -177,7 +186,7 @@ bool ImageRequest::processRequest() // some decoders are removing data when task is complete and there were errors mDecodedRaw = done && mDecodedImageRaw->getData(); } - if (done && mNeedsAux && !mDecodedAux && mFormattedImage.notNull()) + if (done && mNeedsAux && !mDecodedAux) { // Decode aux channel if (!mDecodedImageAux) -- cgit v1.2.3 From 981470e0a1f4d3157d6528b3966922d825e77fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Fri, 9 Feb 2024 01:56:54 +0100 Subject: llimage: BOOL (int) to real bool --- indra/llimage/llimageworker.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'indra/llimage/llimageworker.cpp') diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index 44749343e1..dc99b34c57 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -35,7 +35,7 @@ class ImageRequest { public: ImageRequest(const LLPointer& image, - S32 discard, BOOL needs_aux, + S32 discard, bool needs_aux, const LLPointer& responder); virtual ~ImageRequest(); @@ -48,12 +48,12 @@ private: // input LLPointer mFormattedImage; S32 mDiscardLevel; - BOOL mNeedsAux; + bool mNeedsAux; // output LLPointer mDecodedImageRaw; LLPointer mDecodedImageAux; - BOOL mDecodedRaw; - BOOL mDecodedAux; + bool mDecodedRaw; + bool mDecodedAux; LLPointer mResponder; }; @@ -87,7 +87,7 @@ size_t LLImageDecodeThread::getPending() LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage( const LLPointer& image, S32 discard, - BOOL needs_aux, + bool needs_aux, const LLPointer& responder) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; @@ -124,13 +124,13 @@ LLImageDecodeThread::Responder::~Responder() //---------------------------------------------------------------------------- ImageRequest::ImageRequest(const LLPointer& image, - S32 discard, BOOL needs_aux, + S32 discard, bool needs_aux, const LLPointer& responder) : mFormattedImage(image), mDiscardLevel(discard), mNeedsAux(needs_aux), - mDecodedRaw(FALSE), - mDecodedAux(FALSE), + mDecodedRaw(false), + mDecodedAux(false), mResponder(responder) { } -- cgit v1.2.3 From e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 22 May 2024 21:25:21 +0200 Subject: Fix line endlings --- indra/llimage/llimageworker.cpp | 450 ++++++++++++++++++++-------------------- 1 file changed, 225 insertions(+), 225 deletions(-) (limited to 'indra/llimage/llimageworker.cpp') diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index 62934ccbe1..accbd9964b 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -1,225 +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& image, - S32 discard, - bool needs_aux, - const LLPointer& 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 mFormattedImage; - S32 mDiscardLevel; - U32 mRequestId; - bool mNeedsAux; - // output - LLPointer mDecodedImageRaw; - LLPointer mDecodedImageAux; - bool mDecodedRaw; - bool mDecodedAux; - LLPointer 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& image, - S32 discard, - bool needs_aux, - const LLPointer& 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& image, - S32 discard, - bool needs_aux, - const LLPointer& 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 -} +/** + * @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& image, + S32 discard, + bool needs_aux, + const LLPointer& 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 mFormattedImage; + S32 mDiscardLevel; + U32 mRequestId; + bool mNeedsAux; + // output + LLPointer mDecodedImageRaw; + LLPointer mDecodedImageAux; + bool mDecodedRaw; + bool mDecodedAux; + LLPointer 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& image, + S32 discard, + bool needs_aux, + const LLPointer& 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& image, + S32 discard, + bool needs_aux, + const LLPointer& 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 +} -- cgit v1.2.3 From 77374d9fbce801091f8685b715139b09b5aaa8a1 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Fri, 21 Jun 2024 12:56:57 +0200 Subject: Fix texture fetch request getting canceled if request counter flips over --- indra/llimage/llimageworker.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/llimage/llimageworker.cpp') diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index accbd9964b..bdaef0c653 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -97,6 +97,9 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage( LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; U32 decode_id = ++mDecodeCount; + if (decode_id == 0) + 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)] -- cgit v1.2.3