From 017c02e8d72c994afd1ba63bb5488d585d7a1b51 Mon Sep 17 00:00:00 2001 From: hydrogendeuteride Date: Thu, 4 Dec 2025 16:19:53 +0900 Subject: [PATCH] ADD: async glTF texture preloading --- src/core/engine.cpp | 33 ++++++++++++++++++++++++++++++++- src/core/engine.h | 4 ++++ src/core/engine_ui.cpp | 1 + src/scene/vk_scene.cpp | 10 ++++++++++ src/scene/vk_scene.h | 3 +++ 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/core/engine.cpp b/src/core/engine.cpp index dc10928..e28994f 100644 --- a/src/core/engine.cpp +++ b/src/core/engine.cpp @@ -206,7 +206,7 @@ void VulkanEngine::init() // Async asset loader for background glTF + texture jobs _asyncLoader = std::make_unique(); - _asyncLoader->init(this, _assetManager.get(), _textureCache.get(), 1); + _asyncLoader->init(this, _assetManager.get(), _textureCache.get(), 4); // Optional ray tracing manager if supported and extensions enabled if (_deviceManager->supportsRayQuery() && _deviceManager->supportsAccelerationStructure()) @@ -342,6 +342,7 @@ void VulkanEngine::init_default_data() } addGLTFInstance("mirage", "mirage2000/scene.gltf", glm::mat4(1.0f)); + preloadInstanceTextures("mirage"); _mainDeletionQueue.push_function([&]() { _resourceManager->destroy_image(_whiteImage); @@ -391,6 +392,36 @@ uint32_t VulkanEngine::loadGLTFAsync(const std::string &sceneName, return _asyncLoader->load_gltf_async(sceneName, modelRelativePath, transform); } +void VulkanEngine::preloadInstanceTextures(const std::string &instanceName) +{ + if (!_textureCache || !_sceneManager) + { + return; + } + + auto gltfScene = _sceneManager->getGLTFInstanceScene(instanceName); + if (!gltfScene) + { + return; + } + + uint32_t frame = static_cast(_frameNumber); + uint32_t count = 0; + + // Mark all materials in this glTF scene as used so TextureCache will + // schedule their textures for upload before the object is visible. + for (const auto &[name, material] : gltfScene->materials) + { + if (material && material->data.materialSet) + { + _textureCache->markSetUsed(material->data.materialSet, frame); + ++count; + } + } + + fmt::println("[Engine] Preloaded {} material sets for instance '{}'", count, instanceName); +} + void VulkanEngine::cleanup() { if (_asyncLoader) diff --git a/src/core/engine.h b/src/core/engine.h index fc3078e..ee031a2 100644 --- a/src/core/engine.h +++ b/src/core/engine.h @@ -210,6 +210,10 @@ public: const std::string &modelRelativePath, const glm::mat4 &transform = glm::mat4(1.f)); + // Preload textures for an already-loaded scene instance so they are + // available before the object becomes visible (visibility-driven loading). + void preloadInstanceTextures(const std::string &instanceName); + bool resize_requested{false}; bool freeze_rendering{false}; diff --git a/src/core/engine_ui.cpp b/src/core/engine_ui.cpp index a82b320..10f68c3 100644 --- a/src/core/engine_ui.cpp +++ b/src/core/engine_ui.cpp @@ -467,6 +467,7 @@ namespace glm::mat4 S = glm::scale(glm::mat4(1.0f), glm::vec3(gltfScale[0], gltfScale[1], gltfScale[2])); glm::mat4 M = T * R * S; eng->loadGLTFAsync(gltfName, gltfPath, M); + eng->preloadInstanceTextures(gltfName); } } diff --git a/src/scene/vk_scene.cpp b/src/scene/vk_scene.cpp index 2f70cf3..2fb4019 100644 --- a/src/scene/vk_scene.cpp +++ b/src/scene/vk_scene.cpp @@ -518,6 +518,16 @@ bool SceneManager::removeGLTFInstance(const std::string &name) return true; } +std::shared_ptr SceneManager::getGLTFInstanceScene(const std::string &instanceName) const +{ + auto it = dynamicGLTFInstances.find(instanceName); + if (it != dynamicGLTFInstances.end()) + { + return it->second.scene; + } + return nullptr; +} + bool SceneManager::getGLTFInstanceTransform(const std::string &name, glm::mat4 &outTransform) { auto it = dynamicGLTFInstances.find(name); diff --git a/src/scene/vk_scene.h b/src/scene/vk_scene.h index 9dc7fda..10a47d0 100644 --- a/src/scene/vk_scene.h +++ b/src/scene/vk_scene.h @@ -177,6 +177,9 @@ public: const PickingDebug &getPickingDebug() const { return pickingDebug; } + // Returns the LoadedGLTF scene for a named GLTF instance, or nullptr if not found. + std::shared_ptr getGLTFInstanceScene(const std::string &instanceName) const; + private: EngineContext *_context = nullptr;