diff --git a/src/graphics/stk_tex_manager.cpp b/src/graphics/stk_tex_manager.cpp index ec0a10031..cc79930c3 100644 --- a/src/graphics/stk_tex_manager.cpp +++ b/src/graphics/stk_tex_manager.cpp @@ -28,11 +28,13 @@ #include // ---------------------------------------------------------------------------- -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 diff --git a/src/graphics/stk_tex_manager.hpp b/src/graphics/stk_tex_manager.hpp index d956d526a..05f464879 100644 --- a/src/graphics/stk_tex_manager.hpp +++ b/src/graphics/stk_tex_manager.hpp @@ -23,8 +23,10 @@ #include "utils/singleton.hpp" #include "irrString.h" +#include #include +#include #include #include @@ -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, + 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 diff --git a/src/graphics/threaded_tex_loader.cpp b/src/graphics/threaded_tex_loader.cpp index 0252eecda..fbc04966c 100644 --- a/src/graphics/threaded_tex_loader.cpp +++ b/src/graphics/threaded_tex_loader.cpp @@ -17,6 +17,7 @@ #include "graphics/threaded_tex_loader.hpp" #include "graphics/stk_texture.hpp" +#include "graphics/stk_tex_manager.hpp" #include @@ -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 diff --git a/src/graphics/threaded_tex_loader.hpp b/src/graphics/threaded_tex_loader.hpp index ccd27d310..21dbe08a1 100644 --- a/src/graphics/threaded_tex_loader.hpp +++ b/src/graphics/threaded_tex_loader.hpp @@ -19,12 +19,13 @@ #define HEADER_THREADED_TEX_LOADER_HPP #include "utils/no_copy.hpp" -#include "utils/synchronised.hpp" #include "utils/types.hpp" +#include #include 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 m_finished_loading; - - bool m_destroy, m_locked; - - Synchronised > - m_threaded_loading_textures, m_completed_textures; + std::vector 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