184 lines
5.4 KiB
C++
184 lines
5.4 KiB
C++
/**
|
|
* @file llimageworker.cpp
|
|
* @brief Base class for images.
|
|
*
|
|
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
|
*
|
|
* Copyright (c) 2001-2009, Linden Research, Inc.
|
|
*
|
|
* Second Life Viewer Source Code
|
|
* The source code in this file ("Source Code") is provided by Linden Lab
|
|
* to you under the terms of the GNU General Public License, version 2.0
|
|
* ("GPL"), unless you have obtained a separate licensing agreement
|
|
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
|
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
|
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
|
*
|
|
* There are special exceptions to the terms and conditions of the GPL as
|
|
* it is applied to this Source Code. View the full text of the exception
|
|
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
|
* online at
|
|
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
|
*
|
|
* By copying, modifying or distributing this software, you acknowledge
|
|
* that you have read and understood your obligations described above,
|
|
* and agree to abide by those obligations.
|
|
*
|
|
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
|
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
|
* COMPLETENESS OR PERFORMANCE.
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "linden_common.h"
|
|
|
|
#include "llimageworker.h"
|
|
#include "llimagedxt.h"
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// MAIN THREAD
|
|
LLImageDecodeThread::LLImageDecodeThread(bool threaded)
|
|
: LLQueuedThread("imagedecode", threaded)
|
|
{
|
|
}
|
|
|
|
//virtual
|
|
LLImageDecodeThread::~LLImageDecodeThread()
|
|
{
|
|
}
|
|
|
|
// MAIN THREAD
|
|
// virtual
|
|
S32 LLImageDecodeThread::update(F32 max_time_ms)
|
|
{
|
|
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);
|
|
|
|
bool res = addRequest(req);
|
|
if (!res)
|
|
{
|
|
llerrs << "request added after LLLFSThread::cleanupClass()" << llendl;
|
|
}
|
|
}
|
|
mCreationList.clear();
|
|
S32 res = LLQueuedThread::update(max_time_ms);
|
|
return res;
|
|
}
|
|
|
|
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()
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
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),
|
|
mDiscardLevel(discard),
|
|
mNeedsAux(needs_aux),
|
|
mDecodedRaw(FALSE),
|
|
mDecodedAux(FALSE),
|
|
mResponder(responder)
|
|
{
|
|
}
|
|
|
|
LLImageDecodeThread::ImageRequest::~ImageRequest()
|
|
{
|
|
mDecodedImageRaw = NULL;
|
|
mDecodedImageAux = NULL;
|
|
mFormattedImage = NULL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
// Returns true when done, whether or not decode was successful.
|
|
bool LLImageDecodeThread::ImageRequest::processRequest()
|
|
{
|
|
const F32 decode_time_slice = .1f;
|
|
bool done = true;
|
|
if (!mDecodedRaw && mFormattedImage.notNull())
|
|
{
|
|
// 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); // 1ms
|
|
mDecodedRaw = done;
|
|
}
|
|
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); // 1ms
|
|
mDecodedAux = done;
|
|
}
|
|
|
|
return done;
|
|
}
|
|
|
|
void LLImageDecodeThread::ImageRequest::finishRequest(bool completed)
|
|
{
|
|
if (mResponder.notNull())
|
|
{
|
|
bool success = completed && mDecodedRaw && mDecodedImageRaw->getDataSize() && (!mNeedsAux || mDecodedAux);
|
|
mResponder->completed(success, mDecodedImageRaw, mDecodedImageAux);
|
|
}
|
|
// Will automatically be deleted
|
|
}
|
|
|
|
// 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()
|
|
{
|
|
return mResponder.notNull();
|
|
}
|