diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 5934961b79a486dc501021ab458b773aca39b8a6..3cf361dc5f54b17ee4a93cbc9100d1eca84b0404 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -289,6 +289,35 @@ LLThread::id_t LLThread::getID() const
     return mThreadp ? mThreadp->get_id() : std::thread::id();
 }
 
+ bool LLThread::setPriority(EThreadPriority thread_priority)
+{
+     if(!mThreadp) return false;
+#if LL_WINDOWS
+	int thread_prio = 0;
+	switch (thread_priority)
+	{
+	case LOWEST:
+		thread_prio = THREAD_PRIORITY_LOWEST;
+		break;
+	case BELOW_NORMAL:
+		thread_prio = THREAD_PRIORITY_BELOW_NORMAL;
+		break;
+	default:
+	case NORMAL:
+		thread_prio = THREAD_PRIORITY_NORMAL;
+		break;
+	case ABOVE_NORMAL:
+		thread_prio = THREAD_PRIORITY_ABOVE_NORMAL;
+		break;
+	case HIGHEST:
+		thread_prio = THREAD_PRIORITY_HIGHEST;
+		break;
+	}
+	SetThreadPriority(mThreadp->native_handle(), thread_prio);
+#endif
+    return true;
+}
+
 //============================================================================
 // Called from MAIN THREAD.
 
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index 99d03708de2a5be69e08b1d567aea450360b6c3c..cbc1f42bbc8d33a0ec5cee12f8a9ec87127eab56 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -49,6 +49,15 @@ class LL_COMMON_API LLThread
         QUITTING= 2,    // Someone wants this thread to quit
         CRASHED = -1    // An uncaught exception was thrown by the thread
     } EThreadStatus;
+
+    typedef enum e_thread_priority
+    {
+        LOWEST = 0,
+        BELOW_NORMAL,
+        NORMAL,
+        ABOVE_NORMAL,
+        HIGHEST
+    } EThreadPriority;
     typedef std::thread::id id_t;
 
     LLThread(const std::string& name, apr_pool_t *poolp = NULL);
@@ -85,6 +94,8 @@ class LL_COMMON_API LLThread
 
     id_t getID() const;
 
+    bool setPriority(EThreadPriority thread_priority);
+
 private:
     bool                mPaused;
 
diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp
index d5adf11264cfc25f8de690f545a2a80807355c50..5a3ef043dc7d9955d7b7c7c4ba128e21dfbfd241 100644
--- a/indra/llcommon/threadpool.cpp
+++ b/indra/llcommon/threadpool.cpp
@@ -21,21 +21,46 @@
 #include "llevents.h"
 #include "stringize.h"
 
-LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity):
+LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity, EThreadPrio prio):
     super(name),
     mQueue(name, capacity),
     mName("ThreadPool:" + name),
-    mThreadCount(threads)
+    mThreadCount(threads),
+    mThreadPriority(prio)
 {}
 
 void LL::ThreadPool::start()
 {
     for (size_t i = 0; i < mThreadCount; ++i)
     {
-        std::string tname{ stringize(mName, ':', (i+1), '/', mThreadCount) };
-        mThreads.emplace_back(tname, [this, tname]()
-            {
-                LL_PROFILER_SET_THREAD_NAME(tname.c_str());
+		std::string tname{ stringize(mName, ':', (i + 1), '/', mThreadCount) };
+        EThreadPrio prio = mThreadPriority;
+		mThreads.emplace_back(tname, [this, tname, prio]()
+			{
+				LL_PROFILER_SET_THREAD_NAME(tname.c_str());
+#if LL_WINDOWS
+		        int thread_prio = 0;
+		        switch (prio)
+		        {
+		        case E_LOWEST:
+			        thread_prio = THREAD_PRIORITY_LOWEST;
+			        break;
+		        case E_BELOW_NORMAL:
+			        thread_prio = THREAD_PRIORITY_BELOW_NORMAL;
+			        break;
+		        default:
+		        case E_NORMAL:
+			        thread_prio = THREAD_PRIORITY_NORMAL;
+			        break;
+		        case E_ABOVE_NORMAL:
+			        thread_prio = THREAD_PRIORITY_ABOVE_NORMAL;
+			        break;
+		        case E_HIGHEST:
+			        thread_prio = THREAD_PRIORITY_HIGHEST;
+			        break;
+		        }
+		        SetThreadPriority(GetCurrentThread(), thread_prio);
+#endif
                 run(tname);
             });
     }
diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h
index f8eec3b45744d8a18532811a24901fe84271f62a..be0d856d896b73257e405af3570428a45892a9d7 100644
--- a/indra/llcommon/threadpool.h
+++ b/indra/llcommon/threadpool.h
@@ -27,11 +27,20 @@ namespace LL
     private:
         using super = LLInstanceTracker<ThreadPool, std::string>;
     public:
+        enum EThreadPrio
+        {
+            E_LOWEST = 0,
+            E_BELOW_NORMAL,
+            E_NORMAL,
+            E_ABOVE_NORMAL,
+            E_HIGHEST
+        };
+
         /**
          * Pass ThreadPool a string name. This can be used to look up the
          * relevant WorkQueue.
          */
-        ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024);
+        ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024, EThreadPrio = E_NORMAL);
         virtual ~ThreadPool();
 
         /**
@@ -66,6 +75,7 @@ namespace LL
         std::string mName;
         size_t mThreadCount;
         std::vector<std::pair<std::string, std::thread>> mThreads;
+        EThreadPrio mThreadPriority;
     };
 
 } // namespace LL
diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index c8700fc793c2e12b0a98123f0f7bdfded43ab8f8..6397936a0c2cc8aba56e6b16c0b448315041c619 100644
--- a/indra/llimage/llimageworker.cpp
+++ b/indra/llimage/llimageworker.cpp
@@ -92,10 +92,11 @@ LLImageDecodeThread::LLImageDecodeThread(bool threaded, U32 pool_size)
             pool_size = 2U;  // Use a sane default: 2 cores
         if (pool_size >= 8U)
 		{
-			// Using number of (virtual) cores minus 3 for:
+			// Using number of (virtual) cores minus 4 for:
 			// - main image worker
 			// - viewer main loop thread
 			// - mesh repo thread
+			// - gl image thread
 			// further bound to a maximum of 12 threads (more than that is totally useless, even
 			// when flying over main land with 512m draw distance).
             pool_size = llclamp(pool_size - 4U, 0U, 12U);
@@ -124,6 +125,7 @@ LLImageDecodeThread::LLImageDecodeThread(bool threaded, U32 pool_size)
 	{
 		mThreadPool.push_back(std::make_unique<PoolWorkerThread>(fmt::format("Image Decode Thread {}", i)));
 		mThreadPool[i]->start();
+		mThreadPool[i]->setPriority(LLThread::BELOW_NORMAL);
 	}
 }
 
@@ -133,6 +135,10 @@ LLImageDecodeThread::~LLImageDecodeThread()
     if (sImageThreads > 0) 
 	{
         LL_INFOS() << "Requests failed to queue to pool: " << mFailedRequests << LL_ENDL;
+		for (auto& thread : mThreadPool)
+		{
+			thread->shutdown();
+		}
 	}
 	delete mCreationMutex ;
 }
@@ -344,7 +350,7 @@ bool LLImageDecodeThread::ImageRequest::tut_isOK()
 
 bool LLImageDecodeThread::enqueRequest(ImageRequest * req)
 {
-	for(size_t num_tries = 0, pool_size = mThreadPool.size(); num_tries <= pool_size; ++num_tries)
+	for(size_t num_tries = 0, pool_size = mThreadPool.size(); num_tries < pool_size; ++num_tries)
     {
         if (mLastPoolAllocation >= pool_size)
         {
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index feb4ed844d972908a10613918f9365e6a089a2c5..56d200e109a39d994b095a9f43ead37c51ab4801 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -2522,7 +2522,7 @@ LLImageGLThread::LLImageGLThread(LLWindow* 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)
+    : ThreadPool("LLImageGL", 1, 1024*1024, LL::ThreadPool::E_ABOVE_NORMAL)
     , mWindow(window)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 891a4d3f976c2c8643366210a16fd7cb27887730..2b524ff12ff8cdc17d9f3ff52c8d751bfcecab6c 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -4639,7 +4639,7 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()
 #endif // LL_WINDOWS
 
 inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread()
-    : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE)
+    : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, LL::ThreadPool::E_ABOVE_NORMAL)
 {
     ThreadPool::start();
 }