SL-16202: Use WorkQueue::postTo() for texture create/post handshake.

That is, when LLViewerFetchedTexture::scheduleCreateTexture() wants to call
createTexture() on the LLImageGLThread, but postCreateTexture() on the main
thread, use the "mainloop" WorkQueue to set up the handshake.

Give ThreadPool a public virtual run() method so a subclass can override with
desired behavior. This necessitates a virtual destructor. Add accessors for
embedded WorkQueue (for post calls), ThreadPool name and width (in threads).

Allow LLSimpleton::createInstance() to forward arguments to the subject
constructor.

Make LLImageGLThread an LLSimpleton - that abstraction didn't yet exist at the
time LLImageGLThread was coded. Also derive from ThreadPool rather than
LLThread. Make it a single-thread "pool" with a very large queue capacity.
meow-7.2.2
Nat Goodspeed 2021-11-05 12:33:31 -04:00
parent 834e7ca088
commit ff5496239b
7 changed files with 76 additions and 40 deletions

View File

@ -847,22 +847,24 @@ template<class T>
class LLSimpleton
{
public:
static T* sInstance;
static void createInstance()
{
template <typename... ARGS>
static void createInstance(ARGS&&... args)
{
llassert(sInstance == nullptr);
sInstance = new T();
sInstance = new T(std::forward<ARGS>(args)...);
}
static inline T* getInstance() { return sInstance; }
static inline T& instance() { return *getInstance(); }
static inline bool instanceExists() { return sInstance != nullptr; }
static void deleteSingleton() {
delete sInstance;
sInstance = nullptr;
static void deleteSingleton() {
delete sInstance;
sInstance = nullptr;
}
private:
static T* sInstance;
};
template <class T>

View File

@ -70,6 +70,11 @@ void LL::ThreadPool::close()
void LL::ThreadPool::run(const std::string& name)
{
LL_DEBUGS("ThreadPool") << name << " starting" << LL_ENDL;
mQueue.runUntilClose();
run();
LL_DEBUGS("ThreadPool") << name << " stopping" << LL_ENDL;
}
void LL::ThreadPool::run()
{
mQueue.runUntilClose();
}

View File

@ -30,9 +30,25 @@ namespace LL
* relevant WorkQueue.
*/
ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024);
~ThreadPool();
virtual ~ThreadPool();
/**
* ThreadPool listens for application shutdown messages on the "LLApp"
* LLEventPump. Call close() to shut down this ThreadPool early.
*/
void close();
std::string getName() const { return mName; }
size_t getWidth() const { return mThreads.size(); }
/// obtain a non-const reference to the WorkQueue to post work to it
WorkQueue& getQueue() { return mQueue; }
/**
* Override run() if you need special processing. The default run()
* implementation simply calls WorkQueue::runUntilClose().
*/
virtual void run();
private:
void run(const std::string& name);

View File

@ -172,24 +172,19 @@ BOOL is_little_endian()
return (*c == 0x78) ;
}
LLImageGLThread* LLImageGLThread::sInstance = nullptr;
//static
void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha /* = false */)
{
LL_PROFILE_ZONE_SCOPED;
sSkipAnalyzeAlpha = skip_analyze_alpha;
LLImageGLThread::sInstance = new LLImageGLThread(window);
LLImageGLThread::sInstance->start();
LLImageGLThread::createInstance(window);
}
//static
void LLImageGL::cleanupClass()
{
LL_PROFILE_ZONE_SCOPED;
LLImageGLThread::sInstance->mFunctionQueue.close();
delete LLImageGLThread::sInstance;
LLImageGLThread::sInstance = nullptr;
LLImageGLThread::deleteSingleton();
}
//static
@ -1532,8 +1527,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
}
//if we're on the image loading thread, be sure to delete old_texname and update mTexName on the main thread
if (LLImageGLThread::sInstance != nullptr &&
LLThread::currentID() == LLImageGLThread::sInstance->getID())
if (! on_main_thread())
{
{
LL_PROFILE_ZONE_NAMED("cglt - sync");
@ -2257,7 +2251,11 @@ void LLImageGL::resetCurTexSizebar()
*/
LLImageGLThread::LLImageGLThread(LLWindow* window)
: LLThread("LLImageGL"), mWindow(window)
// We want exactly one thread, but a very large capacity: we never want
// anyone, especially inner-loop render code, to have to block on post()
// because we're full.
: ThreadPool("LLImageGL", 1, 1024*1024)
, mWindow(window)
{
mFinished = false;
@ -2266,9 +2264,11 @@ LLImageGLThread::LLImageGLThread(LLWindow* window)
void LLImageGLThread::run()
{
// We must perform setup on this thread before actually servicing our
// WorkQueue, likewise cleanup afterwards.
mWindow->makeContextCurrent(mContext);
gGL.init();
mFunctionQueue.runUntilClose();
ThreadPool::run();
gGL.shutdown();
mWindow->destroySharedContext(mContext);
}

View File

@ -37,6 +37,7 @@
#include "llunits.h"
#include "llthreadsafequeue.h"
#include "llrender.h"
#include "threadpool.h"
#include "workqueue.h"
class LLTextureAtlas ;
@ -307,7 +308,7 @@ public:
};
class LLImageGLThread : public LLThread
class LLImageGLThread : public LLSimpleton<LLImageGLThread>, LL::ThreadPool
{
public:
LLImageGLThread(LLWindow* window);
@ -316,19 +317,15 @@ public:
template <typename CALLABLE>
bool post(CALLABLE&& func)
{
return mFunctionQueue.postIfOpen(std::forward<CALLABLE>(func));
return getQueue().postIfOpen(std::forward<CALLABLE>(func));
}
void run() override;
// Work Queue for background thread
LL::WorkQueue mFunctionQueue;
private:
LLWindow* mWindow;
void* mContext;
LLAtomicBool mFinished;
static LLImageGLThread* sInstance;
};

View File

@ -679,6 +679,9 @@ void LLViewerTexture::init(bool firstinit)
mVolumeList[LLRender::LIGHT_TEX].clear();
mVolumeList[LLRender::SCULPT_TEX].clear();
mMainQueue = LL::WorkQueue::getInstance("mainloop");
mImageQueue = LL::WorkQueue::getInstance("LLImageGL");
}
//virtual
@ -1622,17 +1625,26 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
{
mNeedsCreateTexture = TRUE;
#if LL_WINDOWS //flip to 0 to revert to single-threaded OpenGL texture uploads
if (!LLImageGLThread::sInstance->post([this]()
{
//actually create the texture on a background thread
createTexture();
LL::WorkQueue::getInstance("mainloop")->post([this]()
{
//finalize on main thread
postCreateTexture();
unref();
});
}))
auto mainq = mMainQueue.lock();
if (mainq)
{
mainq->postTo(
mImageQueue,
// work to be done on LLImageGL worker thread
[this]()
{
//actually create the texture on a background thread
createTexture();
},
// callback to be run on main thread
[this]()
{
//finalize on main thread
postCreateTexture();
unref();
});
}
else
#endif
{
gTextureList.mCreateTextureList.insert(this);

View File

@ -35,6 +35,7 @@
#include "llrender.h"
#include "llmetricperformancetester.h"
#include "httpcommon.h"
#include "workqueue.h"
#include <map>
#include <list>
@ -213,6 +214,9 @@ protected:
//do not use LLPointer here.
LLViewerMediaTexture* mParcelMedia ;
LL::WorkQueue::weak_t mMainQueue;
LL::WorkQueue::weak_t mImageQueue;
static F32 sTexelPixelRatio;
public:
static const U32 sCurrentFileVersion;