diff --git a/src/core/assets/async_loader.cpp b/src/core/assets/async_loader.cpp index e8926ae..6bebb0a 100644 --- a/src/core/assets/async_loader.cpp +++ b/src/core/assets/async_loader.cpp @@ -70,7 +70,8 @@ void AsyncAssetLoader::stop_workers() AsyncAssetLoader::JobID AsyncAssetLoader::load_gltf_async(const std::string &scene_name, const std::string &model_relative_path, - const glm::mat4 &transform) + const glm::mat4 &transform, + bool preload_textures) { if (!_assets) { @@ -83,6 +84,7 @@ AsyncAssetLoader::JobID AsyncAssetLoader::load_gltf_async(const std::string &sce job->scene_name = scene_name; job->model_relative_path = model_relative_path; job->transform = transform; + job->preload_textures = preload_textures; job->progress.store(0.0f, std::memory_order_relaxed); job->state.store(JobState::Pending, std::memory_order_relaxed); @@ -232,6 +234,31 @@ void AsyncAssetLoader::pump_main_thread(SceneManager &scene) job->scene->debugName = job->model_relative_path; } scene.addGLTFInstance(job->scene_name, job->scene, job->transform); + + // Optionally preload textures (same logic as addGLTFInstance) + if (job->preload_textures && _textures && _engine && _engine->_resourceManager) + { + uint32_t frame = static_cast(_engine->_frameNumber); + uint32_t count = 0; + + for (const auto &[name, material] : job->scene->materials) + { + if (material && material->data.materialSet) + { + _textures->markSetUsed(material->data.materialSet, frame); + ++count; + } + } + + if (count > 0) + { + fmt::println("[AsyncLoader] Marked {} materials for preloading in '{}'", + count, job->scene_name); + + // Trigger immediate texture loading pump to start upload + _textures->pumpLoads(*_engine->_resourceManager, _engine->get_current_frame()); + } + } } job->committed_to_scene = true; } diff --git a/src/core/assets/async_loader.h b/src/core/assets/async_loader.h index 2e82d08..46fd879 100644 --- a/src/core/assets/async_loader.h +++ b/src/core/assets/async_loader.h @@ -38,7 +38,8 @@ public: JobID load_gltf_async(const std::string &scene_name, const std::string &model_relative_path, - const glm::mat4 &transform); + const glm::mat4 &transform, + bool preload_textures = false); bool get_job_status(JobID id, JobState &out_state, float &out_progress, std::string *out_error = nullptr); @@ -65,6 +66,7 @@ private: std::string scene_name; std::string model_relative_path; glm::mat4 transform{1.0f}; + bool preload_textures{false}; std::shared_ptr scene; diff --git a/src/core/engine.cpp b/src/core/engine.cpp index e28994f..59157f5 100644 --- a/src/core/engine.cpp +++ b/src/core/engine.cpp @@ -356,7 +356,8 @@ void VulkanEngine::init_default_data() bool VulkanEngine::addGLTFInstance(const std::string &instanceName, const std::string &modelRelativePath, - const glm::mat4 &transform) + const glm::mat4 &transform, + bool preloadTextures) { if (!_assetManager || !_sceneManager) { @@ -377,19 +378,46 @@ bool VulkanEngine::addGLTFInstance(const std::string &instanceName, } _sceneManager->addGLTFInstance(instanceName, *gltf, transform); + + // Optionally preload textures for runtime-added instances + if (preloadTextures && _textureCache && _resourceManager) + { + uint32_t frame = static_cast(_frameNumber); + uint32_t count = 0; + + for (const auto &[name, material] : (*gltf)->materials) + { + if (material && material->data.materialSet) + { + _textureCache->markSetUsed(material->data.materialSet, frame); + ++count; + } + } + + if (count > 0) + { + fmt::println("[Engine] Marked {} materials for preloading in instance '{}'", + count, instanceName); + + // Trigger immediate texture loading pump to start upload + _textureCache->pumpLoads(*_resourceManager, get_current_frame()); + } + } + return true; } uint32_t VulkanEngine::loadGLTFAsync(const std::string &sceneName, const std::string &modelRelativePath, - const glm::mat4 &transform) + const glm::mat4 &transform, + bool preloadTextures) { if (!_asyncLoader || !_assetManager || !_sceneManager) { return 0; } - return _asyncLoader->load_gltf_async(sceneName, modelRelativePath, transform); + return _asyncLoader->load_gltf_async(sceneName, modelRelativePath, transform, preloadTextures); } void VulkanEngine::preloadInstanceTextures(const std::string &instanceName) diff --git a/src/core/engine.h b/src/core/engine.h index ee031a2..6263b6d 100644 --- a/src/core/engine.h +++ b/src/core/engine.h @@ -200,15 +200,19 @@ public: // Convenience helper: load a glTF from assets/models and add it as a runtime instance. // modelRelativePath is relative to the AssetManager model root. + // If preloadTextures is true, textures will be immediately marked for loading to VRAM. bool addGLTFInstance(const std::string &instanceName, const std::string &modelRelativePath, - const glm::mat4 &transform = glm::mat4(1.f)); + const glm::mat4 &transform = glm::mat4(1.f), + bool preloadTextures = false); // Asynchronous glTF load that reports progress via AsyncAssetLoader. // Returns a JobID that can be queried via AsyncAssetLoader. + // If preloadTextures is true, textures will be immediately marked for loading to VRAM. uint32_t loadGLTFAsync(const std::string &sceneName, const std::string &modelRelativePath, - const glm::mat4 &transform = glm::mat4(1.f)); + const glm::mat4 &transform = glm::mat4(1.f), + bool preloadTextures = false); // Preload textures for an already-loaded scene instance so they are // available before the object becomes visible (visibility-driven loading).