Image decode thread pool ported from CoolVL.
parent
005cd67cce
commit
770dc6c865
|
|
@ -442,7 +442,15 @@ S32 LLQueuedThread::processNextRequest()
|
|||
// safe to access req.
|
||||
if (req)
|
||||
{
|
||||
// process request
|
||||
// <FS:ND> Image thread pool from CoolVL
|
||||
if (req->getFlags() & FLAG_ASYNC)
|
||||
{
|
||||
req->processRequest();
|
||||
return getPending();
|
||||
}
|
||||
// </FS:ND>
|
||||
|
||||
// process request
|
||||
bool complete = req->processRequest();
|
||||
|
||||
if (complete)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ public:
|
|||
FLAG_AUTO_COMPLETE = 1,
|
||||
FLAG_AUTO_DELETE = 2, // child-class dependent
|
||||
FLAG_ABORT = 4
|
||||
,FLAG_ASYNC = 8 // <FS:ND/> Image thread pool from CoolVL
|
||||
};
|
||||
|
||||
typedef U32 handle_t;
|
||||
|
|
|
|||
|
|
@ -29,13 +29,100 @@
|
|||
#include "llimageworker.h"
|
||||
#include "llimagedxt.h"
|
||||
|
||||
// <FS:ND> Image thread pool from CoolVL
|
||||
#include "boost/thread.hpp"
|
||||
std::atomic< U32 > s_ChildThreads;
|
||||
|
||||
class PoolWorkerThread : public LLThread
|
||||
{
|
||||
public:
|
||||
PoolWorkerThread(std::string name) : LLThread(name),
|
||||
mCurrentRequest(NULL)
|
||||
{
|
||||
}
|
||||
virtual void run()
|
||||
{
|
||||
while (!isQuitting())
|
||||
{
|
||||
auto *pReq = mCurrentRequest.exchange(nullptr);
|
||||
|
||||
if (pReq)
|
||||
pReq->processRequestIntern();
|
||||
checkPause();
|
||||
}
|
||||
}
|
||||
bool isBusy()
|
||||
{
|
||||
auto *pReq = mCurrentRequest.load();
|
||||
if (!pReq)
|
||||
return false;
|
||||
|
||||
auto status = pReq->getStatus();
|
||||
|
||||
return status == LLQueuedThread::STATUS_INPROGRESS || status == LLQueuedThread::STATUS_INPROGRESS;
|
||||
}
|
||||
|
||||
bool runCondition()
|
||||
{
|
||||
return mCurrentRequest != NULL;
|
||||
}
|
||||
|
||||
bool setRequest(LLImageDecodeThread::ImageRequest* req)
|
||||
{
|
||||
LLImageDecodeThread::ImageRequest* pOld{ nullptr };
|
||||
bool bSuccess = mCurrentRequest.compare_exchange_strong(pOld, req);
|
||||
wake();
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic< LLImageDecodeThread::ImageRequest * > mCurrentRequest;
|
||||
};
|
||||
// </FS:ND>
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// MAIN THREAD
|
||||
LLImageDecodeThread::LLImageDecodeThread(bool threaded)
|
||||
LLImageDecodeThread::LLImageDecodeThread(bool threaded, U32 aSubThreads)
|
||||
: LLQueuedThread("imagedecode", threaded)
|
||||
{
|
||||
mCreationMutex = new LLMutex();
|
||||
|
||||
// <FS:ND> Image thread pool from CoolVL
|
||||
if (aSubThreads == 0)
|
||||
{
|
||||
aSubThreads = boost::thread::hardware_concurrency();
|
||||
if (!aSubThreads)
|
||||
aSubThreads = 4U; // Use a sane default: 4 cores
|
||||
if (aSubThreads > 8U)
|
||||
{
|
||||
// Using number of (virtual) cores - 1 (for the main image worker
|
||||
// thread) - 1 (for the viewer main loop thread), further bound to
|
||||
// a maximum of 32 threads (more than that is totally useless, even
|
||||
// when flying over main land with 512m draw distance).
|
||||
aSubThreads = llmin(aSubThreads - 2U, 32U);
|
||||
}
|
||||
else if (aSubThreads > 2U)
|
||||
{
|
||||
// Using number of (virtual) cores - 1 (for the main image worker
|
||||
// thread).
|
||||
--aSubThreads;
|
||||
}
|
||||
}
|
||||
else if (aSubThreads == 1) // Disable if only 1
|
||||
aSubThreads = 0;
|
||||
|
||||
s_ChildThreads = aSubThreads;
|
||||
for (U32 i = 0; i < aSubThreads; ++i)
|
||||
{
|
||||
std::stringstream strm;
|
||||
strm << "imagedecodethread" << (i + 1);
|
||||
|
||||
mThreadPool.push_back(std::make_shared< PoolWorkerThread>(strm.str()));
|
||||
mThreadPool[i]->start();
|
||||
}
|
||||
// </FS:ND>
|
||||
}
|
||||
|
||||
//virtual
|
||||
|
|
@ -53,9 +140,12 @@ S32 LLImageDecodeThread::update(F32 max_time_ms)
|
|||
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);
|
||||
ImageRequest* req = new ImageRequest(info.handle, info.image,
|
||||
info.priority, info.discard, info.needs_aux,
|
||||
info.responder);
|
||||
info.priority, info.discard, info.needs_aux,
|
||||
info.responder, this);
|
||||
|
||||
bool res = addRequest(req);
|
||||
if (!res)
|
||||
|
|
@ -95,15 +185,21 @@ LLImageDecodeThread::Responder::~Responder()
|
|||
|
||||
LLImageDecodeThread::ImageRequest::ImageRequest(handle_t handle, LLImageFormatted* image,
|
||||
U32 priority, S32 discard, BOOL needs_aux,
|
||||
LLImageDecodeThread::Responder* responder)
|
||||
LLImageDecodeThread::Responder* responder,
|
||||
LLImageDecodeThread *aQueue)
|
||||
: LLQueuedThread::QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE),
|
||||
mFormattedImage(image),
|
||||
mDiscardLevel(discard),
|
||||
mNeedsAux(needs_aux),
|
||||
mDecodedRaw(FALSE),
|
||||
mDecodedAux(FALSE),
|
||||
mResponder(responder)
|
||||
mResponder(responder),
|
||||
mQueue( aQueue ) // <FS:ND/> Image thread pool from CoolVL
|
||||
{
|
||||
//<FS:ND> Image thread pool from CoolVL
|
||||
if (s_ChildThreads > 0)
|
||||
mFlags |= FLAG_ASYNC;
|
||||
// </FS:ND>
|
||||
}
|
||||
|
||||
LLImageDecodeThread::ImageRequest::~ImageRequest()
|
||||
|
|
@ -118,6 +214,21 @@ LLImageDecodeThread::ImageRequest::~ImageRequest()
|
|||
|
||||
// Returns true when done, whether or not decode was successful.
|
||||
bool LLImageDecodeThread::ImageRequest::processRequest()
|
||||
{
|
||||
// <FS:ND> Image thread pool from CoolVL
|
||||
|
||||
// If not async, decode using this thread
|
||||
if ((mFlags & FLAG_ASYNC) == 0)
|
||||
return processRequestIntern();
|
||||
|
||||
// Try to dispatch to a new thread, if this isn't possible decode on this thread
|
||||
if (!mQueue->enqueRequest(this))
|
||||
return processRequestIntern();
|
||||
return true;
|
||||
// </FS:ND>
|
||||
}
|
||||
|
||||
bool LLImageDecodeThread::ImageRequest::processRequestIntern()
|
||||
{
|
||||
const F32 decode_time_slice = .1f;
|
||||
bool done = true;
|
||||
|
|
@ -172,6 +283,15 @@ bool LLImageDecodeThread::ImageRequest::processRequest()
|
|||
mDecodedAux = done && mDecodedImageAux->getData();
|
||||
}
|
||||
|
||||
//<FS:ND> Image thread pool from CoolVL
|
||||
if (mFlags & FLAG_ASYNC)
|
||||
{
|
||||
setStatus(STATUS_COMPLETE);
|
||||
finishRequest(true);
|
||||
// always autocomplete
|
||||
mQueue->completeRequest(mHashKey);
|
||||
}
|
||||
// </FS:ND>
|
||||
return done;
|
||||
}
|
||||
|
||||
|
|
@ -191,3 +311,16 @@ bool LLImageDecodeThread::ImageRequest::tut_isOK()
|
|||
{
|
||||
return mResponder.notNull();
|
||||
}
|
||||
|
||||
bool LLImageDecodeThread::enqueRequest(ImageRequest * req)
|
||||
{
|
||||
for (auto &pThread : mThreadPool)
|
||||
{
|
||||
if (!pThread->isBusy())
|
||||
{
|
||||
if( pThread->setRequest(req) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@
|
|||
#include "llpointer.h"
|
||||
#include "llworkerthread.h"
|
||||
|
||||
// <FS:ND/> Image thread pool
|
||||
class PoolWorkerThread;
|
||||
|
||||
class LLImageDecodeThread : public LLQueuedThread
|
||||
{
|
||||
public:
|
||||
|
|
@ -50,9 +53,10 @@ public:
|
|||
public:
|
||||
ImageRequest(handle_t handle, LLImageFormatted* image,
|
||||
U32 priority, S32 discard, BOOL needs_aux,
|
||||
LLImageDecodeThread::Responder* responder);
|
||||
LLImageDecodeThread::Responder* responder, LLImageDecodeThread *aQueue);
|
||||
|
||||
/*virtual*/ bool processRequest();
|
||||
bool processRequestIntern();
|
||||
/*virtual*/ void finishRequest(bool completed);
|
||||
|
||||
// Used by unit tests to check the consitency of the request instance
|
||||
|
|
@ -66,13 +70,18 @@ public:
|
|||
// output
|
||||
LLPointer<LLImageRaw> mDecodedImageRaw;
|
||||
LLPointer<LLImageRaw> mDecodedImageAux;
|
||||
LLImageDecodeThread * mQueue; // <FS:ND> Image thread pool from CoolVL
|
||||
BOOL mDecodedRaw;
|
||||
BOOL mDecodedAux;
|
||||
LLPointer<LLImageDecodeThread::Responder> mResponder;
|
||||
};
|
||||
|
||||
public:
|
||||
LLImageDecodeThread(bool threaded = true);
|
||||
// <FS:ND> Image thread pool from CoolVL
|
||||
//LLImageDecodeThread(bool threaded = true);
|
||||
LLImageDecodeThread(bool threaded = true, U32 aSubThreads = 0 );
|
||||
// </FS:ND>
|
||||
|
||||
virtual ~LLImageDecodeThread();
|
||||
|
||||
handle_t decodeImage(LLImageFormatted* image,
|
||||
|
|
@ -99,6 +108,11 @@ private:
|
|||
typedef std::list<creation_info> creation_list_t;
|
||||
creation_list_t mCreationList;
|
||||
LLMutex* mCreationMutex;
|
||||
|
||||
// <FS:ND> Image thread pool from CoolVL
|
||||
std::vector< std::shared_ptr< PoolWorkerThread > > mThreadPool;
|
||||
bool enqueRequest(ImageRequest*);
|
||||
// <FS:ND>
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25661,5 +25661,16 @@ Change of this parameter will affect the layout of buttons in notification toast
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSImageDecodeThreads</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Amount of threads to use for image decoding. 0 = autodetect, 1 = 0ff, >1 number of threads. Needs restart</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
|
|
|
|||
|
|
@ -2577,8 +2577,12 @@ bool LLAppViewer::initThreads()
|
|||
|
||||
LLLFSThread::initClass(enable_threads && false);
|
||||
|
||||
//<FS:ND> Image thread pool from CoolVL
|
||||
U32 imageThreads = gSavedSettings.getU32("FSImageDecodeThreads");
|
||||
// </FS:ND>
|
||||
|
||||
// Image decoding
|
||||
LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true);
|
||||
LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true, imageThreads);
|
||||
LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true);
|
||||
LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(),
|
||||
sImageDecodeThread,
|
||||
|
|
|
|||
Loading…
Reference in New Issue