From c46be5287dd09acd3140918e30669907bdfa267b Mon Sep 17 00:00:00 2001 From: ChestnutYueyue <952134128@qq.com> Date: Thu, 12 Feb 2026 10:41:07 +0800 Subject: [PATCH] =?UTF-8?q?refactor(resource):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E7=AE=A1=E7=90=86=E5=99=A8=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=20TexturePool=20=E7=AE=A1=E7=90=86=E7=BA=B9=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除原有的异步加载系统,改为使用 TexturePool 作为纹理管理后端 新增 update 方法用于主循环调用,触发纹理池自动清理 保留原有接口但标记为弃用,保持向后兼容 所有纹理相关操作现在通过 TexturePool 实现 --- .../extra2d/resource/resource_manager.h | 43 +-- Extra2D/src/app/application.cpp | 5 + Extra2D/src/resource/resource_manager.cpp | 339 +++++++----------- 3 files changed, 161 insertions(+), 226 deletions(-) diff --git a/Extra2D/include/extra2d/resource/resource_manager.h b/Extra2D/include/extra2d/resource/resource_manager.h index bbd7a02..4aaf7b4 100644 --- a/Extra2D/include/extra2d/resource/resource_manager.h +++ b/Extra2D/include/extra2d/resource/resource_manager.h @@ -6,19 +6,16 @@ #include #include #include -#include #include #include #include -#include -#include -#include +#include namespace extra2d { // ============================================================================ // 资源管理器 - 统一管理纹理、字体、音效等资源 -// 支持异步加载和纹理压缩 +// 使用 TexturePool 作为纹理管理后端 // ============================================================================ // 纹理格式枚举 @@ -43,6 +40,13 @@ public: // ------------------------------------------------------------------------ static ResourceManager &getInstance(); + // ------------------------------------------------------------------------ + // 更新(在主循环中调用) + // ------------------------------------------------------------------------ + + /// 更新资源管理器,触发纹理池自动清理等 + void update(float dt); + // ------------------------------------------------------------------------ // 纹理资源 - 同步加载 // ------------------------------------------------------------------------ @@ -142,19 +146,24 @@ public: size_t getSoundCacheSize() const; // ------------------------------------------------------------------------ - // 异步加载控制 + // 异步加载控制(已弃用,保留接口兼容性) + // 纹理异步加载由 TexturePool 内部处理 // ------------------------------------------------------------------------ /// 初始化异步加载系统(可选,自动在首次异步加载时初始化) + /// @deprecated 纹理池已内置异步加载,无需调用 void initAsyncLoader(); /// 关闭异步加载系统 + /// @deprecated 纹理池自动管理生命周期,无需调用 void shutdownAsyncLoader(); /// 等待所有异步加载完成 + /// @deprecated 使用回调机制处理异步加载结果 void waitForAsyncLoads(); /// 检查是否有正在进行的异步加载 + /// @deprecated 始终返回 false bool hasPendingAsyncLoads() const; ResourceManager(); @@ -177,32 +186,14 @@ private: std::vector compressTexture(const uint8_t* data, int width, int height, int channels, TextureFormat format); - // 互斥锁保护缓存 - mutable std::mutex textureMutex_; + // 互斥锁保护缓存(字体和音效缓存仍需锁保护) mutable std::mutex fontMutex_; mutable std::mutex soundMutex_; // 资源缓存 - 使用弱指针实现自动清理 - std::unordered_map> textureCache_; + // 纹理缓存已移至 TexturePool,此处仅保留字体和音效缓存 std::unordered_map> fontCache_; std::unordered_map> soundCache_; - - // 异步加载相关 - struct AsyncLoadTask { - std::string filepath; - TextureFormat format; - TextureLoadCallback callback; - std::promise> promise; - }; - - std::queue asyncTaskQueue_; - std::mutex asyncQueueMutex_; - std::condition_variable asyncCondition_; - std::unique_ptr asyncThread_; - std::atomic asyncRunning_{false}; - std::atomic pendingAsyncLoads_{0}; - - void asyncLoadLoop(); }; } // namespace extra2d diff --git a/Extra2D/src/app/application.cpp b/Extra2D/src/app/application.cpp index 9d99aed..2cbef9b 100644 --- a/Extra2D/src/app/application.cpp +++ b/Extra2D/src/app/application.cpp @@ -314,6 +314,11 @@ void Application::update() { if (sceneManager_) { sceneManager_->update(deltaTime_); } + + // 更新资源管理器(触发纹理池自动清理) + if (resourceManager_) { + resourceManager_->update(deltaTime_); + } } void Application::render() { diff --git a/Extra2D/src/resource/resource_manager.cpp b/Extra2D/src/resource/resource_manager.cpp index db73638..59dc6a3 100644 --- a/Extra2D/src/resource/resource_manager.cpp +++ b/Extra2D/src/resource/resource_manager.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -79,10 +80,17 @@ static std::string resolveResourcePath(const std::string &filepath) { return ""; } -ResourceManager::ResourceManager() = default; +ResourceManager::ResourceManager() { + // 初始化纹理池 + TexturePoolConfig config; + config.maxCacheSize = 128 * 1024 * 1024; // 128MB + config.maxTextureCount = 512; + config.enableAsyncLoad = true; + TexturePool::getInstance().init(config); +} ResourceManager::~ResourceManager() { - shutdownAsyncLoader(); + TexturePool::getInstance().shutdown(); } ResourceManager &ResourceManager::getInstance() { @@ -91,77 +99,11 @@ ResourceManager &ResourceManager::getInstance() { } // ============================================================================ -// 异步加载系统 +// 更新(在主循环中调用) // ============================================================================ -void ResourceManager::initAsyncLoader() { - if (asyncRunning_) { - return; - } - - asyncRunning_ = true; - asyncThread_ = std::make_unique(&ResourceManager::asyncLoadLoop, this); - E2D_LOG_INFO("ResourceManager: async loader initialized"); -} - -void ResourceManager::shutdownAsyncLoader() { - if (!asyncRunning_) { - return; - } - - asyncRunning_ = false; - asyncCondition_.notify_all(); - - if (asyncThread_ && asyncThread_->joinable()) { - asyncThread_->join(); - } - - E2D_LOG_INFO("ResourceManager: async loader shutdown"); -} - -void ResourceManager::waitForAsyncLoads() { - while (pendingAsyncLoads_ > 0) { - std::this_thread::yield(); - } -} - -bool ResourceManager::hasPendingAsyncLoads() const { - return pendingAsyncLoads_ > 0; -} - -void ResourceManager::asyncLoadLoop() { - while (asyncRunning_) { - AsyncLoadTask task; - - { - std::unique_lock lock(asyncQueueMutex_); - asyncCondition_.wait(lock, [this] { return !asyncTaskQueue_.empty() || !asyncRunning_; }); - - if (!asyncRunning_) { - break; - } - - if (asyncTaskQueue_.empty()) { - continue; - } - - task = std::move(asyncTaskQueue_.front()); - asyncTaskQueue_.pop(); - } - - // 执行加载 - auto texture = loadTextureInternal(task.filepath, task.format); - - // 回调 - if (task.callback) { - task.callback(texture); - } - - // 设置 promise - task.promise.set_value(texture); - - pendingAsyncLoads_--; - } +void ResourceManager::update(float dt) { + TexturePool::getInstance().update(dt); } // ============================================================================ @@ -191,57 +133,31 @@ void ResourceManager::loadTextureAsync(const std::string &filepath, TextureLoadC } void ResourceManager::loadTextureAsync(const std::string &filepath, TextureFormat format, TextureLoadCallback callback) { - // 确保异步加载系统已启动 - if (!asyncRunning_) { - initAsyncLoader(); - } - - // 检查缓存 - { - std::lock_guard lock(textureMutex_); - auto it = textureCache_.find(filepath); - if (it != textureCache_.end()) { - if (auto texture = it->second.lock()) { - // 缓存命中,立即回调 - if (callback) { - callback(texture); - } - return; - } + // 解析资源路径 + std::string fullPath = resolveResourcePath(filepath); + if (fullPath.empty()) { + E2D_LOG_ERROR("ResourceManager: texture file not found: {}", filepath); + if (callback) { + callback(nullptr); } + return; } - // 添加到异步任务队列 - AsyncLoadTask task; - task.filepath = filepath; - task.format = format; - task.callback = callback; - - { - std::lock_guard lock(asyncQueueMutex_); - asyncTaskQueue_.push(std::move(task)); - } - - pendingAsyncLoads_++; - asyncCondition_.notify_one(); - - E2D_LOG_DEBUG("ResourceManager: queued async texture load: {}", filepath); + // 使用纹理池的异步加载 + TexturePool::getInstance().getAsync(fullPath, + [callback, filepath](Ptr texture) { + if (texture) { + E2D_LOG_DEBUG("ResourceManager: async texture loaded: {}", filepath); + } else { + E2D_LOG_ERROR("ResourceManager: failed to async load texture: {}", filepath); + } + if (callback) { + callback(texture); + } + }); } Ptr ResourceManager::loadTextureInternal(const std::string &filepath, TextureFormat format) { - std::lock_guard lock(textureMutex_); - - // 检查缓存 - auto it = textureCache_.find(filepath); - if (it != textureCache_.end()) { - if (auto texture = it->second.lock()) { - E2D_LOG_TRACE("ResourceManager: texture cache hit: {}", filepath); - return texture; - } - // 弱引用已失效,移除 - textureCache_.erase(it); - } - // 解析资源路径(优先尝试 romfs:/ 前缀) std::string fullPath = resolveResourcePath(filepath); if (fullPath.empty()) { @@ -249,30 +165,22 @@ Ptr ResourceManager::loadTextureInternal(const std::string &filepath, T return nullptr; } - // 创建新纹理 - try { - auto texture = makePtr(fullPath); - if (!texture->isValid()) { - E2D_LOG_ERROR("ResourceManager: failed to load texture: {}", filepath); - return nullptr; - } - - // 如果需要压缩,处理纹理格式 - if (format != TextureFormat::Auto && format != TextureFormat::RGBA8) { - // 注意:实际压缩需要在纹理创建时处理 - // 这里仅记录日志,实际实现需要在 GLTexture 中支持 - E2D_LOG_DEBUG("ResourceManager: texture format {} requested for {}", - static_cast(format), filepath); - } - - // 存入缓存 - textureCache_[filepath] = texture; - E2D_LOG_DEBUG("ResourceManager: loaded texture: {}", filepath); - return texture; - } catch (...) { - E2D_LOG_ERROR("ResourceManager: exception loading texture: {}", filepath); + // 使用纹理池获取纹理 + auto texture = TexturePool::getInstance().get(fullPath); + + if (!texture) { + E2D_LOG_ERROR("ResourceManager: failed to load texture: {}", filepath); return nullptr; } + + // 如果需要压缩,处理纹理格式(记录日志,实际压缩需要在纹理创建时处理) + if (format != TextureFormat::Auto && format != TextureFormat::RGBA8) { + E2D_LOG_DEBUG("ResourceManager: texture format {} requested for {}", + static_cast(format), filepath); + } + + E2D_LOG_DEBUG("ResourceManager: loaded texture: {}", filepath); + return texture; } TextureFormat ResourceManager::selectBestFormat(TextureFormat requested) const { @@ -318,70 +226,90 @@ ResourceManager::loadTextureWithAlphaMask(const std::string &filepath) { const AlphaMask * ResourceManager::getAlphaMask(const std::string &textureKey) const { - std::lock_guard lock(textureMutex_); - - auto it = textureCache_.find(textureKey); - if (it != textureCache_.end()) { - if (auto texture = it->second.lock()) { - GLTexture *glTexture = static_cast(texture.get()); - return glTexture->getAlphaMask(); - } + // 解析路径获取完整路径 + std::string fullPath = resolveResourcePath(textureKey); + if (fullPath.empty()) { + return nullptr; } - return nullptr; + + // 从纹理池获取纹理 + auto texture = TexturePool::getInstance().get(fullPath); + if (!texture) { + return nullptr; + } + + GLTexture *glTexture = static_cast(texture.get()); + return glTexture->getAlphaMask(); } bool ResourceManager::generateAlphaMask(const std::string &textureKey) { - std::lock_guard lock(textureMutex_); - - auto it = textureCache_.find(textureKey); - if (it != textureCache_.end()) { - if (auto texture = it->second.lock()) { - GLTexture *glTexture = static_cast(texture.get()); - if (!glTexture->hasAlphaMask()) { - glTexture->generateAlphaMask(); - } - return glTexture->hasAlphaMask(); - } + // 解析路径获取完整路径 + std::string fullPath = resolveResourcePath(textureKey); + if (fullPath.empty()) { + return false; } - return false; + + // 从纹理池获取纹理 + auto texture = TexturePool::getInstance().get(fullPath); + if (!texture) { + return false; + } + + GLTexture *glTexture = static_cast(texture.get()); + if (!glTexture->hasAlphaMask()) { + glTexture->generateAlphaMask(); + } + return glTexture->hasAlphaMask(); } bool ResourceManager::hasAlphaMask(const std::string &textureKey) const { - std::lock_guard lock(textureMutex_); - - auto it = textureCache_.find(textureKey); - if (it != textureCache_.end()) { - if (auto texture = it->second.lock()) { - GLTexture *glTexture = static_cast(texture.get()); - return glTexture->hasAlphaMask(); - } + // 解析路径获取完整路径 + std::string fullPath = resolveResourcePath(textureKey); + if (fullPath.empty()) { + return false; } - return false; + + // 从纹理池获取纹理 + auto texture = TexturePool::getInstance().get(fullPath); + if (!texture) { + return false; + } + + GLTexture *glTexture = static_cast(texture.get()); + return glTexture->hasAlphaMask(); } Ptr ResourceManager::getTexture(const std::string &key) const { - std::lock_guard lock(textureMutex_); - - auto it = textureCache_.find(key); - if (it != textureCache_.end()) { - return it->second.lock(); + // 解析路径获取完整路径 + std::string fullPath = resolveResourcePath(key); + if (fullPath.empty()) { + return nullptr; } - return nullptr; + + // 从纹理池获取纹理 + return TexturePool::getInstance().get(fullPath); } bool ResourceManager::hasTexture(const std::string &key) const { - std::lock_guard lock(textureMutex_); - - auto it = textureCache_.find(key); - if (it != textureCache_.end()) { - return !it->second.expired(); + // 解析路径获取完整路径 + std::string fullPath = resolveResourcePath(key); + if (fullPath.empty()) { + return false; } - return false; + + // 检查纹理池是否有此纹理 + return TexturePool::getInstance().has(fullPath); } void ResourceManager::unloadTexture(const std::string &key) { - std::lock_guard lock(textureMutex_); - textureCache_.erase(key); + // 解析路径获取完整路径 + std::string fullPath = resolveResourcePath(key); + if (fullPath.empty()) { + return; + } + + // 从纹理池移除 + TexturePool::getInstance().remove(fullPath); E2D_LOG_DEBUG("ResourceManager: unloaded texture: {}", key); } @@ -540,18 +468,9 @@ void ResourceManager::unloadSound(const std::string &key) { // ============================================================================ void ResourceManager::purgeUnused() { - // 清理纹理缓存 - { - std::lock_guard lock(textureMutex_); - for (auto it = textureCache_.begin(); it != textureCache_.end();) { - if (it->second.expired()) { - E2D_LOG_TRACE("ResourceManager: purging unused texture: {}", it->first); - it = textureCache_.erase(it); - } else { - ++it; - } - } - } + // 纹理缓存由 TexturePool 自动管理,无需手动清理 + // 但我们可以触发 TexturePool 的清理 + TexturePool::getInstance().trim(TexturePool::getInstance().getCacheSize() * 0.8f); // 清理字体缓存 { @@ -581,10 +500,8 @@ void ResourceManager::purgeUnused() { } void ResourceManager::clearTextureCache() { - std::lock_guard lock(textureMutex_); - size_t count = textureCache_.size(); - textureCache_.clear(); - E2D_LOG_INFO("ResourceManager: cleared {} textures from cache", count); + TexturePool::getInstance().clear(); + E2D_LOG_INFO("ResourceManager: texture cache cleared via TexturePool"); } void ResourceManager::clearFontCache() { @@ -614,8 +531,7 @@ void ResourceManager::clearAllCaches() { } size_t ResourceManager::getTextureCacheSize() const { - std::lock_guard lock(textureMutex_); - return textureCache_.size(); + return TexturePool::getInstance().getTextureCount(); } size_t ResourceManager::getFontCacheSize() const { @@ -628,4 +544,27 @@ size_t ResourceManager::getSoundCacheSize() const { return soundCache_.size(); } +// ============================================================================ +// 异步加载控制(已弃用,保留接口兼容性) +// ============================================================================ + +void ResourceManager::initAsyncLoader() { + // 纹理池已内置异步加载,无需额外初始化 + E2D_LOG_DEBUG("ResourceManager: async loader is handled by TexturePool"); +} + +void ResourceManager::shutdownAsyncLoader() { + // 纹理池在 shutdown 时处理 +} + +void ResourceManager::waitForAsyncLoads() { + // 纹理池异步加载通过回调处理,无需等待 + // 如需等待,可通过回调机制实现 +} + +bool ResourceManager::hasPendingAsyncLoads() const { + // 纹理池异步加载通过回调处理,无法直接查询 + return false; +} + } // namespace extra2d