diff --git a/src/graphics/central_settings.cpp b/src/graphics/central_settings.cpp index 2096b6602..9ad4e7495 100644 --- a/src/graphics/central_settings.cpp +++ b/src/graphics/central_settings.cpp @@ -490,7 +490,7 @@ bool CentralVideoSettings::isARBPixelBufferObjectUsable() const bool CentralVideoSettings::supportsThreadedTextureLoading() const { - return isARBPixelBufferObjectUsable() && supportsAsyncInstanceUpload(); + return isARBPixelBufferObjectUsable() && isARBBufferStorageUsable(); } #endif // !SERVER_ONLY diff --git a/src/graphics/stk_tex_manager.cpp b/src/graphics/stk_tex_manager.cpp index 19e5749c3..ff22a82dc 100644 --- a/src/graphics/stk_tex_manager.cpp +++ b/src/graphics/stk_tex_manager.cpp @@ -24,11 +24,11 @@ #include "utils/string_utils.hpp" #include "utils/log.hpp" +#include #include // ---------------------------------------------------------------------------- -STKTexManager::STKTexManager() : m_pbo(0), m_pbo_ptr(NULL), m_pbo_size(0), - m_thread_size(0), m_tlt_added(0) +STKTexManager::STKTexManager() : m_pbo(0), m_thread_size(0), m_tlt_added(0) { #ifndef SERVER_ONLY if (CVS->supportsThreadedTextureLoading()) @@ -40,18 +40,20 @@ STKTexManager::STKTexManager() : m_pbo(0), m_pbo_ptr(NULL), m_pbo_size(0), Log::info("STKTexManager", "%d thread(s) for texture loading," " each capacity %d MB", m_thread_size, each_capacity / 1024 / 1024); - GLuint pbo; - uint8_t* pbo_ptr; + glGenBuffers(1, &m_pbo); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_pbo); + glBufferStorage(GL_PIXEL_UNPACK_BUFFER, max_pbo_size, NULL, + GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | + GL_MAP_COHERENT_BIT); + uint8_t* pbo_ptr = (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, + 0, max_pbo_size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | + GL_MAP_COHERENT_BIT); + size_t offset = 0; for (unsigned i = 0; i < m_thread_size; i++) { - glGenBuffers(1, &pbo); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); - glBufferStorage(GL_PIXEL_UNPACK_BUFFER, each_capacity, NULL, - GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); - pbo_ptr = (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, - each_capacity, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); m_all_tex_loaders.push_back(new ThreadedTexLoader(each_capacity, - pbo, pbo_ptr)); + offset, pbo_ptr + offset)); + offset += each_capacity; } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } @@ -285,6 +287,7 @@ 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) @@ -321,10 +324,36 @@ void STKTexManager::uploadBatch() { #if !(defined(SERVER_ONLY) || defined(USE_GLES2)) if (!CVS->supportsThreadedTextureLoading()) return; + bool uploaded = false; for (ThreadedTexLoader* ttl : m_all_tex_loaders) { if (ttl->finishedLoading()) + { + if (!uploaded) + { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_pbo); + uploaded = true; + } ttl->handleCompletedTextures(); + } + } + if (uploaded) + { + GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + GLenum reason = glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, 0); + if (reason != GL_ALREADY_SIGNALED) + { + do + { + reason = glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, + 1000000); + } + while (reason == GL_TIMEOUT_EXPIRED); + } + glDeleteSync(sync); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + for (ThreadedTexLoader* ttl : m_all_tex_loaders) + ttl->unlockCompletedTextures(); } #endif } // uploadBatch diff --git a/src/graphics/stk_tex_manager.hpp b/src/graphics/stk_tex_manager.hpp index 36b016eef..1fcae1898 100644 --- a/src/graphics/stk_tex_manager.hpp +++ b/src/graphics/stk_tex_manager.hpp @@ -21,12 +21,9 @@ #include "graphics/gl_headers.hpp" #include "utils/no_copy.hpp" #include "utils/singleton.hpp" -#include "utils/synchronised.hpp" #include "irrString.h" -#include -#include #include #include #include @@ -47,15 +44,11 @@ private: * This is used to specify details like: "while loading kart '...'" */ std::string m_texture_error_message; - Synchronised > m_threaded_loading_textures; - std::vector m_all_tex_loaders; GLuint m_pbo; - uint8_t* m_pbo_ptr; - - unsigned m_pbo_size, m_thread_size, m_tlt_added; + unsigned m_thread_size, m_tlt_added; // ------------------------------------------------------------------------ STKTexture* findTextureInFileSystem(const std::string& filename, @@ -143,35 +136,6 @@ public: } // getTexture // ------------------------------------------------------------------------ void uploadBatch(); - // ------------------------------------------------------------------------ - const unsigned getThreadedLoadingTextureNum() const - { - m_threaded_loading_textures.lock(); - const unsigned num = m_threaded_loading_textures.getData().size(); - m_threaded_loading_textures.unlock(); - return num; - } - // ------------------------------------------------------------------------ - STKTexture* getThreadedLoadingTexture(unsigned num) const - { - m_threaded_loading_textures.lock(); - assert(num < m_threaded_loading_textures.getData().size()); - STKTexture* t = m_threaded_loading_textures.getData()[num]; - m_threaded_loading_textures.unlock(); - return t; - } - // ------------------------------------------------------------------------ - const bool isThreadedLoaderEmpty() const - { - m_threaded_loading_textures.lock(); - const bool empty = m_threaded_loading_textures.getData().empty(); - m_threaded_loading_textures.unlock(); - return empty; - } - // ------------------------------------------------------------------------ - uint8_t* getPBOPtr() { return m_pbo_ptr; } - // ------------------------------------------------------------------------ - unsigned getNumLoadingThread() const { return m_thread_size; } }; // STKTexManager diff --git a/src/graphics/threaded_tex_loader.cpp b/src/graphics/threaded_tex_loader.cpp index f5d0b869c..0252eecda 100644 --- a/src/graphics/threaded_tex_loader.cpp +++ b/src/graphics/threaded_tex_loader.cpp @@ -86,8 +86,7 @@ void ThreadedTexLoader::handleCompletedTextures() { #if !(defined(SERVER_ONLY) || defined(USE_GLES2)) m_completed_textures.lock(); - glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_pbo); + m_locked = true; size_t offset = 0; for (STKTexture* stkt : m_completed_textures.getData()) { @@ -95,26 +94,11 @@ void ThreadedTexLoader::handleCompletedTextures() glBindTexture(GL_TEXTURE_2D, stkt->getOpenGLTextureName()); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stkt->getSize().Width, stkt->getSize().Height, stkt->isSingleChannel() ? GL_RED : GL_BGRA, - GL_UNSIGNED_BYTE, (const void*)offset); + GL_UNSIGNED_BYTE, (const void*)(m_pbo_offset + offset)); if (stkt->hasMipMaps()) glGenerateMipmap(GL_TEXTURE_2D); offset += stkt->getTextureSize(); } - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); m_completed_textures.getData().clear(); - GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - GLenum reason = glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, 0); - if (reason != GL_ALREADY_SIGNALED) - { - do - { - reason = - glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000000); - } - while (reason == GL_TIMEOUT_EXPIRED); - } - glDeleteSync(sync); - m_finished_loading.setAtomic(false); - m_completed_textures.unlock(); #endif } // handleCompletedTextures diff --git a/src/graphics/threaded_tex_loader.hpp b/src/graphics/threaded_tex_loader.hpp index 9cc632bdd..91c4225ac 100644 --- a/src/graphics/threaded_tex_loader.hpp +++ b/src/graphics/threaded_tex_loader.hpp @@ -18,7 +18,6 @@ #ifndef HEADER_THREADED_TEX_LOADER_HPP #define HEADER_THREADED_TEX_LOADER_HPP -#include "graphics/gl_headers.hpp" #include "utils/no_copy.hpp" #include "utils/synchronised.hpp" #include "utils/types.hpp" @@ -33,7 +32,7 @@ class ThreadedTexLoader : public NoCopy private: const unsigned m_tex_capacity; - GLuint m_pbo; + const size_t m_pbo_offset; uint8_t* m_pbo_ptr; @@ -45,7 +44,7 @@ private: Synchronised m_finished_loading; - bool m_destroy; + bool m_destroy, m_locked; Synchronised > m_threaded_loading_textures, m_completed_textures; @@ -54,10 +53,11 @@ public: // ------------------------------------------------------------------------ static void* startRoutine(void *obj); // ------------------------------------------------------------------------ - ThreadedTexLoader(unsigned capacity, GLuint pbo, uint8_t* pbo_ptr) - : m_tex_capacity(capacity), m_pbo(pbo), m_pbo_ptr(pbo_ptr), - m_tex_size_loaded(0), m_waiting_timeout(0), - m_finished_loading(false), m_destroy(false) + ThreadedTexLoader(unsigned capacity, size_t offset, uint8_t* pbo_ptr) + : 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) { pthread_cond_init(&m_cond_request, NULL); pthread_create(&m_thread, NULL, &startRoutine, this); @@ -81,6 +81,14 @@ public: bool finishedLoading() const { return m_finished_loading.getAtomic(); } // ------------------------------------------------------------------------ void handleCompletedTextures(); + // ------------------------------------------------------------------------ + void unlockCompletedTextures() + { + if (!m_locked) return; + m_locked = false; + m_finished_loading.setAtomic(false); + m_completed_textures.unlock(); + } }; // ThreadedTexLoader