diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 0993daaa8b..cb9d06dce1 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -685,11 +685,6 @@ void OpenGLDisplayPlugin::present() { } incrementPresentCount(); - { - PROFILE_RANGE_EX(render, "recycle", 0xff00ff00, frameId) - _gpuContext->recycle(); - } - if (_currentFrame) { { withPresentThreadLock([&] { diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index 6fb0d7b152..f93d430152 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -772,7 +772,7 @@ void GLBackend::recycle() const { GLVariableAllocationSupport::manageMemory(); GLVariableAllocationSupport::_frameTexturesCreated = 0; - + Texture::KtxStorage::releaseOpenKtxFiles(); } void GLBackend::setCameraCorrection(const Mat4& correction) { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 1877b494cf..06208179e0 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -321,13 +321,18 @@ public: void reset() override { } + // Don't keep files open forever. We close them at the beginning of each frame (GLBackend::recycle) + static void releaseOpenKtxFiles(); + protected: std::shared_ptr maybeOpenFile() const; - mutable std::mutex _cacheFileCreateMutex; - mutable std::mutex _cacheFileWriteMutex; + mutable std::shared_ptr _cacheFileMutex { std::make_shared() }; mutable std::weak_ptr _cacheFile; + static std::vector, std::shared_ptr>> _cachedKtxFiles; + static std::mutex _cachedKtxFilesMutex; + std::string _filename; cache::FilePointer _cacheEntry; std::atomic _minMipLevelAvailable; diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 08fc4ec101..883d9abf15 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -23,6 +23,9 @@ using namespace gpu; using PixelsPointer = Texture::PixelsPointer; using KtxStorage = Texture::KtxStorage; +std::vector, std::shared_ptr>> KtxStorage::_cachedKtxFiles; +std::mutex KtxStorage::_cachedKtxFilesMutex; + struct GPUKTXPayload { using Version = uint8; @@ -187,36 +190,44 @@ KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) { } } +// maybeOpenFile should be called with _cacheFileMutex already held to avoid modifying the file from multiple threads std::shared_ptr KtxStorage::maybeOpenFile() const { - // 1. Try to get the shared ptr - // 2. If it doesn't exist, grab the mutex around its creation - // 3. If it was created before we got the mutex, return it - // 4. Otherwise, create it - + // Try to get the shared_ptr std::shared_ptr file = _cacheFile.lock(); if (file) { return file; } + // If the file isn't open, create it and save a weak_ptr to it + file = std::make_shared(_filename.c_str()); + _cacheFile = file; + { - std::lock_guard lock{ _cacheFileCreateMutex }; - - file = _cacheFile.lock(); - if (file) { - return file; - } - - file = std::make_shared(_filename.c_str()); - _cacheFile = file; + // Add the shared_ptr to the global list of open KTX files, to be released at the beginning of the next present thread frame + std::lock_guard lock(_cachedKtxFilesMutex); + _cachedKtxFiles.emplace_back(file, _cacheFileMutex); } return file; } +void KtxStorage::releaseOpenKtxFiles() { + std::vector, std::shared_ptr>> localKtxFiles; + { + std::lock_guard lock(_cachedKtxFilesMutex); + localKtxFiles.swap(_cachedKtxFiles); + } + for (auto& cacheFileAndMutex : localKtxFiles) { + std::lock_guard lock(*(cacheFileAndMutex.second)); + cacheFileAndMutex.first.reset(); + } +} + PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const { auto faceOffset = _ktxDescriptor->getMipFaceTexelsOffset(level, face); auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face); if (faceSize != 0 && faceOffset != 0) { + std::lock_guard lock(*_cacheFileMutex); auto file = maybeOpenFile(); if (file) { auto storageView = file->createView(faceSize, faceOffset); @@ -262,6 +273,7 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor return; } + std::lock_guard lock(*_cacheFileMutex); auto file = maybeOpenFile(); if (!file) { qWarning() << "Failed to open file to assign mip data " << QString::fromStdString(_filename); @@ -279,8 +291,6 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor imageData += ktx::IMAGE_SIZE_WIDTH; { - std::lock_guard lock { _cacheFileWriteMutex }; - if (level != _minMipLevelAvailable - 1) { qWarning() << "Invalid level to be stored"; return;