Try to use priority queue

This commit is contained in:
Benau 2017-03-10 20:43:40 +08:00
parent 6b3441d2a0
commit 85011791e4
4 changed files with 114 additions and 65 deletions

View File

@ -28,11 +28,13 @@
#include <algorithm>
// ----------------------------------------------------------------------------
STKTexManager::STKTexManager() : m_pbo(0), m_thread_size(0), m_tlt_added(0)
STKTexManager::STKTexManager() : m_pbo(0), m_thread_size(0)
{
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
if (CVS->supportsThreadedTextureLoading())
{
pthread_mutex_init(&m_threaded_load_textures_mutex, NULL);
pthread_cond_init(&m_cond_request, NULL);
m_thread_size = HardwareStats::getNumProcessors();
m_thread_size = core::clamp(m_thread_size, 1, 8);
static const unsigned max_pbo_size = 32 * 1024 * 1024;
@ -52,7 +54,8 @@ STKTexManager::STKTexManager() : m_pbo(0), m_thread_size(0), m_tlt_added(0)
for (int i = 0; i < m_thread_size; i++)
{
m_all_tex_loaders.push_back(new ThreadedTexLoader(each_capacity,
offset, pbo_ptr + offset));
offset, pbo_ptr + offset, &m_threaded_load_textures_mutex,
&m_cond_request, this));
offset += each_capacity;
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
@ -65,8 +68,12 @@ STKTexManager::STKTexManager() : m_pbo(0), m_thread_size(0), m_tlt_added(0)
STKTexManager::~STKTexManager()
{
removeTexture(NULL/*texture*/, true/*remove_all*/);
for (ThreadedTexLoader* ttl : m_all_tex_loaders)
delete ttl;
if (CVS->supportsThreadedTextureLoading())
{
pthread_cond_destroy(&m_cond_request);
for (ThreadedTexLoader* ttl : m_all_tex_loaders)
delete ttl;
}
} // ~STKTexManager
// ----------------------------------------------------------------------------
@ -137,8 +144,7 @@ video::ITexture* STKTexManager::getTexture(const std::string& path, bool srgb,
}
if (new_texture->useThreadedLoading())
{
m_all_tex_loaders[m_tlt_added++ % m_thread_size]
->addTexture(new_texture);
addThreadedLoadTexture(new_texture);
}
}
uploadBatch();
@ -252,14 +258,12 @@ core::stringw STKTexManager::reloadTexture(const irr::core::stringw& name)
p.second->reload();
if (p.second->useThreadedLoading())
{
m_all_tex_loaders[m_tlt_added++ % m_thread_size]
->addTexture(p.second);
addThreadedLoadTexture(p.second);
uploadBatch();
}
Log::info("STKTexManager", "%s reloaded",
p.second->getName().getPtr());
}
m_tlt_added = 0;
return L"All textures reloaded.";
}
@ -281,8 +285,7 @@ core::stringw STKTexManager::reloadTexture(const irr::core::stringw& name)
p.second->reload();
if (p.second->useThreadedLoading())
{
m_all_tex_loaders[m_tlt_added++ % m_thread_size]
->addTexture(p.second);
addThreadedLoadTexture(p.second);
uploadBatch();
}
result += tex_name.c_str();
@ -290,7 +293,6 @@ core::stringw STKTexManager::reloadTexture(const irr::core::stringw& name)
break;
}
}
m_tlt_added = 0;
}
if (result.empty())
return L"Texture(s) not found!";
@ -301,7 +303,6 @@ core::stringw STKTexManager::reloadTexture(const irr::core::stringw& name)
// ----------------------------------------------------------------------------
void STKTexManager::reset()
{
m_tlt_added = 0;
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
if (!CVS->isAZDOEnabled()) return;
for (auto p : m_all_textures)
@ -341,6 +342,7 @@ void STKTexManager::uploadBatch()
bool uploaded = false;
for (ThreadedTexLoader* ttl : m_all_tex_loaders)
{
ttl->lock();
if (ttl->finishedLoading())
{
if (!uploaded)
@ -350,6 +352,10 @@ void STKTexManager::uploadBatch()
}
ttl->handleCompletedTextures();
}
else
{
ttl->unlock();
}
}
if (uploaded)
{
@ -367,7 +373,14 @@ void STKTexManager::uploadBatch()
glDeleteSync(sync);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
for (ThreadedTexLoader* ttl : m_all_tex_loaders)
ttl->unlockCompletedTextures();
ttl->unlock();
}
#endif
} // uploadBatch
// ----------------------------------------------------------------------------
bool STKTexManager::SmallestTexture::operator()
(const STKTexture *a, const STKTexture *b) const
{
return a->getTextureSize() > b->getTextureSize();
} // SmallestTexture::operator

View File

@ -23,8 +23,10 @@
#include "utils/singleton.hpp"
#include "irrString.h"
#include <pthread.h>
#include <string>
#include <queue>
#include <unordered_map>
#include <vector>
@ -50,7 +52,17 @@ private:
int m_thread_size;
unsigned m_tlt_added;
class SmallestTexture
{
public:
bool operator() (const STKTexture *a, const STKTexture *b) const;
};
std::priority_queue<STKTexture*, std::vector<STKTexture*>,
SmallestTexture> m_threaded_load_textures;
pthread_mutex_t m_threaded_load_textures_mutex;
pthread_cond_t m_cond_request;
// ------------------------------------------------------------------------
STKTexture* findTextureInFileSystem(const std::string& filename,
@ -138,6 +150,22 @@ public:
} // getTexture
// ------------------------------------------------------------------------
void uploadBatch();
// ------------------------------------------------------------------------
STKTexture* getThreadedLoadTexture()
{ return m_threaded_load_textures.top(); }
// ------------------------------------------------------------------------
void addThreadedLoadTexture(STKTexture* t)
{
pthread_mutex_lock(&m_threaded_load_textures_mutex);
m_threaded_load_textures.push(t);
pthread_cond_signal(&m_cond_request);
pthread_mutex_unlock(&m_threaded_load_textures_mutex);
}
// ------------------------------------------------------------------------
void removeThreadedLoadTexture() { m_threaded_load_textures.pop(); }
// ------------------------------------------------------------------------
bool isThreadedLoadTexturesEmpty()
{ return m_threaded_load_textures.empty(); }
}; // STKTexManager

View File

@ -17,6 +17,7 @@
#include "graphics/threaded_tex_loader.hpp"
#include "graphics/stk_texture.hpp"
#include "graphics/stk_tex_manager.hpp"
#include <cassert>
@ -26,69 +27,70 @@ void* ThreadedTexLoader::startRoutine(void *obj)
ThreadedTexLoader* ttl = (ThreadedTexLoader*)obj;
while (!ttl->m_destroy)
{
if (ttl->finishedLoading())
pthread_mutex_lock(&ttl->m_mutex);
bool finished = ttl->finishedLoading();
pthread_mutex_unlock(&ttl->m_mutex);
if (finished)
{
continue;
}
ttl->m_threaded_loading_textures.lock();
bool queue_empty = ttl->m_threaded_loading_textures.getData().empty();
ttl->m_completed_textures.lock();
bool no_unloaded_tex = ttl->m_completed_textures.getData().empty();
ttl->m_completed_textures.unlock();
bool no_unloaded_tex = ttl->m_completed_textures.empty();
pthread_mutex_lock(ttl->m_texture_queue_mutex);
bool queue_empty = ttl->m_stktm->isThreadedLoadTexturesEmpty();
bool waiting = queue_empty && no_unloaded_tex;
while (waiting)
{
pthread_cond_wait(&ttl->m_cond_request,
ttl->m_threaded_loading_textures.getMutex());
waiting = ttl->m_threaded_loading_textures.getData().empty();
pthread_cond_wait(ttl->m_cond_request, ttl->m_texture_queue_mutex);
waiting = ttl->m_stktm->isThreadedLoadTexturesEmpty();
}
if (queue_empty)
{
if (ttl->m_waiting_timeout++ > 10)
{
ttl->m_finished_loading.setAtomic(true);
pthread_mutex_lock(&ttl->m_mutex);
ttl->m_finished_loading = true;
ttl->m_tex_size_loaded = 0;
ttl->m_waiting_timeout = 0;
pthread_mutex_unlock(&ttl->m_mutex);
}
ttl->m_threaded_loading_textures.unlock();
pthread_mutex_unlock(ttl->m_texture_queue_mutex);
continue;
}
else
{
ttl->m_waiting_timeout = 0;
}
STKTexture* target_tex = ttl->m_threaded_loading_textures.getData()[0];
STKTexture* target_tex = ttl->m_stktm->getThreadedLoadTexture();
if (target_tex->getTextureSize() + ttl->m_tex_size_loaded >
ttl->m_tex_capacity)
{
ttl->m_finished_loading.setAtomic(true);
pthread_mutex_lock(&ttl->m_mutex);
ttl->m_finished_loading = true;
ttl->m_tex_size_loaded = 0;
ttl->m_waiting_timeout = 0;
ttl->m_threaded_loading_textures.unlock();
pthread_mutex_unlock(&ttl->m_mutex);
pthread_mutex_unlock(ttl->m_texture_queue_mutex);
continue;
}
ttl->m_threaded_loading_textures.getData().erase
(ttl->m_threaded_loading_textures.getData().begin());
ttl->m_threaded_loading_textures.unlock();
ttl->m_stktm->removeThreadedLoadTexture();
pthread_mutex_unlock(ttl->m_texture_queue_mutex);
target_tex->threadedReload(ttl->m_pbo_ptr + ttl->m_tex_size_loaded);
target_tex->cleanThreadedLoader();
ttl->m_tex_size_loaded += target_tex->getTextureSize();
ttl->m_completed_textures.lock();
ttl->m_completed_textures.getData().push_back(target_tex);
ttl->m_completed_textures.unlock();
ttl->m_completed_textures.push_back(target_tex);
}
pthread_exit(NULL);
return NULL;
} // startRoutine
// ----------------------------------------------------------------------------
void ThreadedTexLoader::handleCompletedTextures()
{
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
m_completed_textures.lock();
m_locked = true;
assert(m_locked);
size_t offset = 0;
for (STKTexture* stkt : m_completed_textures.getData())
for (STKTexture* stkt : m_completed_textures)
{
assert(!stkt->useThreadedLoading());
glBindTexture(GL_TEXTURE_2D, stkt->getOpenGLTextureName());
@ -99,6 +101,6 @@ void ThreadedTexLoader::handleCompletedTextures()
glGenerateMipmap(GL_TEXTURE_2D);
offset += stkt->getTextureSize();
}
m_completed_textures.getData().clear();
m_completed_textures.clear();
#endif
} // handleCompletedTextures

View File

@ -19,12 +19,13 @@
#define HEADER_THREADED_TEX_LOADER_HPP
#include "utils/no_copy.hpp"
#include "utils/synchronised.hpp"
#include "utils/types.hpp"
#include <pthread.h>
#include <vector>
class STKTexture;
class STKTexManager;
class ThreadedTexLoader : public NoCopy
{
@ -35,58 +36,63 @@ private:
uint8_t* m_pbo_ptr;
pthread_mutex_t m_mutex;
pthread_mutex_t* m_texture_queue_mutex;
pthread_cond_t* m_cond_request;
STKTexManager* m_stktm;
unsigned m_tex_size_loaded, m_waiting_timeout;
pthread_t m_thread;
pthread_cond_t m_cond_request;
bool m_finished_loading, m_destroy, m_locked;
Synchronised<bool> m_finished_loading;
bool m_destroy, m_locked;
Synchronised<std::vector<STKTexture*> >
m_threaded_loading_textures, m_completed_textures;
std::vector<STKTexture*> m_completed_textures;
public:
// ------------------------------------------------------------------------
static void* startRoutine(void *obj);
// ------------------------------------------------------------------------
ThreadedTexLoader(unsigned capacity, size_t offset, uint8_t* pbo_ptr)
ThreadedTexLoader(unsigned capacity, size_t offset, uint8_t* pbo_ptr,
pthread_mutex_t* mutex, pthread_cond_t* cond,
STKTexManager* stktm)
: m_tex_capacity(capacity), m_pbo_offset(offset),
m_pbo_ptr(pbo_ptr), m_tex_size_loaded(0),
m_waiting_timeout(0), m_finished_loading(false),
m_destroy(false), m_locked(false)
m_pbo_ptr(pbo_ptr), m_texture_queue_mutex(mutex),
m_cond_request(cond), m_stktm(stktm),
m_tex_size_loaded(0), m_waiting_timeout(0),
m_finished_loading(false), m_destroy(false),
m_locked(false)
{
pthread_cond_init(&m_cond_request, NULL);
pthread_mutex_init(&m_mutex, NULL);
pthread_create(&m_thread, NULL, &startRoutine, this);
}
// ------------------------------------------------------------------------
~ThreadedTexLoader()
{
m_destroy = true;
pthread_cond_destroy(&m_cond_request);
pthread_mutex_destroy(&m_mutex);
pthread_join(m_thread, NULL);
}
// ------------------------------------------------------------------------
void addTexture(STKTexture* t)
{
m_threaded_loading_textures.lock();
m_threaded_loading_textures.getData().push_back(t);
pthread_cond_signal(&m_cond_request);
m_threaded_loading_textures.unlock();
}
// ------------------------------------------------------------------------
bool finishedLoading() const { return m_finished_loading.getAtomic(); }
bool finishedLoading() const { return m_finished_loading; }
// ------------------------------------------------------------------------
void handleCompletedTextures();
// ------------------------------------------------------------------------
void unlockCompletedTextures()
void lock()
{
pthread_mutex_lock(&m_mutex);
m_locked = true;
}
// ------------------------------------------------------------------------
void unlock()
{
if (!m_locked) return;
m_locked = false;
m_finished_loading.setAtomic(false);
m_completed_textures.unlock();
m_finished_loading = false;
pthread_mutex_unlock(&m_mutex);
}
}; // ThreadedTexLoader