diff --git a/Editor/Source/Editor/EditorLayer.cpp b/Editor/Source/Editor/EditorLayer.cpp index d32e70d3..a6a3d4a3 100644 --- a/Editor/Source/Editor/EditorLayer.cpp +++ b/Editor/Source/Editor/EditorLayer.cpp @@ -73,6 +73,8 @@ void EditorLayer::OnUpdate() Nuake::Engine::EndDraw(); Nuake::Input::Update(); + + RID::ExecuteRemaps(); } void EditorLayer::OnDetach() diff --git a/Nuake/Source/Nuake/FileSystem/File.cpp b/Nuake/Source/Nuake/FileSystem/File.cpp index 82c5f995..409189e3 100644 --- a/Nuake/Source/Nuake/FileSystem/File.cpp +++ b/Nuake/Source/Nuake/FileSystem/File.cpp @@ -79,10 +79,10 @@ FileType File::GetFileType() const return FileType::Mesh; } - if (ext == ".glb" || ext == ".gltf" || ext == ".fbx") - { - return FileType::MeshAsset; - } + //if (ext == ".glb" || ext == ".gltf" || ext == ".fbx") + //{ + // return FileType::MeshAsset; + //} if (ext == ".html") { diff --git a/Nuake/Source/Nuake/FileSystem/FileSystem.cpp b/Nuake/Source/Nuake/FileSystem/FileSystem.cpp index 41b01962..6684075d 100644 --- a/Nuake/Source/Nuake/FileSystem/FileSystem.cpp +++ b/Nuake/Source/Nuake/FileSystem/FileSystem.cpp @@ -7,9 +7,16 @@ #include "Directory.h" #include "File.h" +#include "Nuake/Resource/Bakers/AssetBakerManager.h" +#include "Nuake/Resource/Resolvers/ResolverManager.h" + #include "filewatch/FileWatch.hpp" #include +#include +#include +#include "Nuake/Resource/RID.h" + using namespace Nuake; @@ -113,8 +120,11 @@ std::vector> FileSystem::GetAllFiles(const FileType fileType) void FileSystem::SetRootDirectory(const std::string path) { Root = path; - RootFileWatch = CreateRef>( - path, [&](const std::string& path, const filewatch::Event& event) + + if (!RootFileWatch) + { + RootFileWatch = CreateRef>( + path, [&](const std::string& path, const filewatch::Event& event) { std::string normalizedPath = String::ReplaceSlash(path); @@ -133,23 +143,59 @@ void FileSystem::SetRootDirectory(const std::string path) std::string extension = filePath.extension().string(); Ref newImportedFile = CreateRef(parentDirectory, FileSystem::RelativeToAbsolute(normalizedPath), name, extension); parentDirectory->Files.push_back(newImportedFile); + + AssetBakerManager::Get().OnNewAssetDetected(newImportedFile); } - if(Ref file = GetFile(normalizedPath); file) + if (Ref file = GetFile(normalizedPath); file) { - if (file->GetFileType() == FileType::Unknown) - { - return; - } - if (event == filewatch::Event::modified) { file->SetHasBeenModified(true); + + AssetBakerManager::Get().OnNewAssetDetected(file); + + if (file->GetExtension() != ".nkmesh") + { + return; + } + + ResourceManifest& manifest = Nuake::ResourceManager::Manifest; + UUID oldUUID = manifest.GetResourceUUID(file->GetRelativePath()); + + if(oldUUID == 0) + { + return; + } + + Logger::Log("Old UUID" + std::to_string(oldUUID), "UUID", VERBOSE); + + //Ref newFile = AssetBakerManager::Get().Bake(file); + auto& resolver = ResourceResolverManager::Get(); + if (resolver.IsFileTypeResolvable(file->GetExtension())) + { + // Read uuid from file + const UUID& uuid = resolver.ResolveUUID(file); + Logger::Log("new UUID" + std::to_string(uuid), "UUID", VERBOSE); + manifest.RegisterResource(uuid, file->GetRelativePath()); + RID::QueueRemap(oldUUID, uuid); + } + + // manifest.RegisterResource(uuid, file->GetRelativePath()); + // + // ResourceManager::RemapResource(oldUUID, uuid); + // + // if (ResourceManager::IsResourceLoaded(uuid)) + // { + // ResourceManager::ReloadResource(uuid); + // } + //} } - } } - ); + ); + } + Scan(); } diff --git a/Nuake/Source/Nuake/FileSystem/FileSystem.h b/Nuake/Source/Nuake/FileSystem/FileSystem.h index 38767827..e0cbad12 100644 --- a/Nuake/Source/Nuake/FileSystem/FileSystem.h +++ b/Nuake/Source/Nuake/FileSystem/FileSystem.h @@ -3,6 +3,7 @@ #include "FileTypes.h" #include +#include namespace filewatch { @@ -17,8 +18,15 @@ namespace Nuake using OnFileFunc = std::function)>; + struct FileProcessRequest + { + Ref FileToProcess; + }; + class FileSystem { + private: + public: static std::string Root; static Ref RootDirectory; diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VkResources.h b/Nuake/Source/Nuake/Rendering/Vulkan/VkResources.h index f9db0e3b..fc4ef282 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VkResources.h +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VkResources.h @@ -87,7 +87,7 @@ namespace Nuake constexpr uint32_t MAX_MODEL_MATRIX = 3000; constexpr uint32_t MAX_MATERIAL = 3000; - constexpr uint32_t MAX_TEXTURES = 500; + constexpr uint32_t MAX_TEXTURES = 1000; constexpr uint32_t MAX_CAMERAS = 100; constexpr uint32_t MAX_LIGHTS = 100; diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.cpp index f7ab3741..ae4aa4c9 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.cpp @@ -34,6 +34,7 @@ #include "vk_mem_alloc.h" #include +#include #include bool NKUseValidationLayer = false; @@ -767,9 +768,11 @@ bool VkRenderer::Draw() return true; } +std::mutex queueMutex; void VkRenderer::EndDraw() { + std::lock_guard lock(queueMutex); if (FrameSkipped) { return; @@ -856,8 +859,10 @@ void VkRenderer::DrawImgui(VkCommandBuffer cmd, VkImageView targetImageView) vkCmdEndRendering(cmd); } + void VkRenderer::ImmediateSubmit(std::function&& function) { + std::lock_guard lock(queueMutex); VK_CALL(vkResetFences(Device, 1, &ImguiFence)); VK_CALL(vkResetCommandBuffer(ImguiCommandBuffer, 0)); diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanResources.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanResources.cpp index 673b80d0..343e30df 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanResources.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanResources.cpp @@ -312,16 +312,19 @@ void GPUResources::CreateBindlessLayout() void GPUResources::RecreateBindlessTextures() { // Ideally wed have update bit enabled ondescriptors - vkQueueWaitIdle(VkRenderer::Get().GPUQueue); + //vkQueueWaitIdle(VkRenderer::Get().GPUQueue); + if (!TexturesDescriptor) { CreateBindlessLayout(); } BindlessTextureMapping.clear(); + std::vector imageInfos(Images.size()); auto allTextures = GetAllTextures(); - for (size_t i = 0; i < Images.size(); i++) { + for (size_t i = 0; i < Images.size(); i++) + { imageInfos[i].imageView = allTextures[i]->GetImageView(); imageInfos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; BindlessTextureMapping[allTextures[i]->GetID()] = i; diff --git a/Nuake/Source/Nuake/Resource/Bakers/AssetBakerManager.h b/Nuake/Source/Nuake/Resource/Bakers/AssetBakerManager.h index f372a011..7d060d1b 100644 --- a/Nuake/Source/Nuake/Resource/Bakers/AssetBakerManager.h +++ b/Nuake/Source/Nuake/Resource/Bakers/AssetBakerManager.h @@ -1,10 +1,15 @@ #pragma once #include "IAssetBaker.h" #include "Nuake/Core/Core.h" +#include "Nuake/Core/Logger.h" + #include "Nuake/FileSystem/File.h" -#include +#include +#include #include +#include +#include namespace Nuake { @@ -29,13 +34,77 @@ namespace Nuake } } + void OnAssetReimport(const Ref& file) + { + const std::string extension = file->GetExtension(); + if (Bakers.find(extension) == Bakers.end()) + { + return; + } + + Bakers[extension]->Bake(file); + Logger::Log("New file baked: " + file->GetRelativePath(), "baker", VERBOSE); + } + + bool WaitForFileReady(const std::string& path, int timeoutMs = 10000) + { + using namespace std::chrono_literals; + namespace fs = std::filesystem; + + const int checkIntervalMs = 500; + auto startTime = std::chrono::steady_clock::now(); + std::uintmax_t lastSize = 0; + + while (true) + { + if (!fs::exists(path)) + { + std::this_thread::sleep_for(std::chrono::milliseconds(checkIntervalMs)); + continue; + } + + auto currentSize = fs::file_size(path); + if (currentSize == lastSize && currentSize > 0) + { + std::this_thread::sleep_for(std::chrono::milliseconds(checkIntervalMs)); + if (fs::file_size(path) == currentSize) + return true; + } + + lastSize = currentSize; + + if (std::chrono::steady_clock::now() - startTime > std::chrono::milliseconds(timeoutMs)) + return false; + + std::this_thread::sleep_for(std::chrono::milliseconds(checkIntervalMs)); + } + } + + void OnNewAssetDetected(const Ref& file) + { + const std::string extension = file->GetExtension(); + if (Bakers.find(extension) == Bakers.end()) + { + return; + } + + // Wait until the file is fully copied/written + if (!WaitForFileReady(file->GetAbsolutePath())) + { + Logger::Log("File was not ready in time: " + file->GetRelativePath(), "baker", WARNING); + return; + } + + Bakers[extension]->Bake(file); + Logger::Log("New file baked: " + file->GetRelativePath(), "baker", VERBOSE); + } + Ref Bake(const Ref& file) { const std::string extension = file->GetExtension(); if(Bakers.find(extension) == Bakers.end()) { - assert(false && "Baker not found for asset type"); - return nullptr; + return file; } return Bakers[extension]->Bake(file); diff --git a/Nuake/Source/Nuake/Resource/RID.cpp b/Nuake/Source/Nuake/Resource/RID.cpp index 8efe5917..241863a9 100644 --- a/Nuake/Source/Nuake/Resource/RID.cpp +++ b/Nuake/Source/Nuake/Resource/RID.cpp @@ -1,4 +1,7 @@ #include "RID.h" - using namespace Nuake; + +std::vector RID::Handles; +std::queue RID::RemapQueue; +std::mutex RID::RemapMutex; \ No newline at end of file diff --git a/Nuake/Source/Nuake/Resource/RID.h b/Nuake/Source/Nuake/Resource/RID.h index 6df8713d..664612c2 100644 --- a/Nuake/Source/Nuake/Resource/RID.h +++ b/Nuake/Source/Nuake/Resource/RID.h @@ -10,13 +10,73 @@ namespace Nuake class RID { + private: + struct RemapRequest + { + UUID Old; + UUID New; + }; + + static std::vector Handles; + static std::queue RemapQueue; + static std::mutex RemapMutex; + public: UUID ID; Ref Data; - RID() : ID(0), Data(nullptr) {} - RID(UUID id) : ID(id) {} + RID() : ID(0), Data(nullptr) + { + Handles.push_back(this); + } + RID(UUID id) : ID(id) + { + Handles.push_back(this); + } + ~RID() + { + std::remove_if(Handles.begin(), Handles.end(), [this](const RID* rid) { return rid == this; }); + } + + static void ExecuteRemaps() + { + std::lock_guard lock(RemapMutex); + while (!RemapQueue.empty()) + { + auto& request = RemapQueue.front(); + uint32_t remappedCount = 0; + for (auto& handle : Handles) + { + if (handle->ID == request.Old) + { + handle->ID = request.New; + + if (handle->Data) + { + handle->Data = nullptr; + } + + remappedCount++; + } + } + RemapQueue.pop(); + + Logger::Log("Remapped " + std::to_string(remappedCount), "RID", VERBOSE); + } + } + + static void QueueRemap(const UUID& old, const UUID& newUUID) + { + std::lock_guard lock(RemapMutex); + if (old == newUUID) + { + return; + } + + RemapQueue.push({ old, newUUID }); + } + public: template Ref Get() diff --git a/Nuake/Source/Nuake/Resource/ResourceManager.h b/Nuake/Source/Nuake/Resource/ResourceManager.h index 226e49a7..99bce0d8 100644 --- a/Nuake/Source/Nuake/Resource/ResourceManager.h +++ b/Nuake/Source/Nuake/Resource/ResourceManager.h @@ -25,6 +25,11 @@ namespace Nuake static ResourceManifest Manifest; static Ref GetResource(const UUID& uuid); + static void RemapResource(const UUID& oldUUID, const UUID& newUUID) + { + m_Resources[oldUUID] = m_Resources[newUUID]; + } + static void RegisterResource(Ref resource) { m_Resources[resource->ID] = resource; @@ -35,6 +40,13 @@ namespace Nuake return m_Resources.find(uuid) != m_Resources.end(); } + static bool ReloadResource(const UUID& uuid) + { + m_Resources.erase(uuid); + + return true; + } + static Ref RegisterUnregisteredRessource(Ref file) { Ref resolvedResource = ResourceResolverManager::Get().Resolve(file); diff --git a/Nuake/Source/Nuake/Resource/ResourceManifest.h b/Nuake/Source/Nuake/Resource/ResourceManifest.h index 79dbe2d7..49dc05be 100644 --- a/Nuake/Source/Nuake/Resource/ResourceManifest.h +++ b/Nuake/Source/Nuake/Resource/ResourceManifest.h @@ -5,6 +5,7 @@ #include "Nuake/FileSystem/FileSystem.h" #include +#include #include namespace Nuake @@ -16,10 +17,11 @@ namespace Nuake private: std::map PathToMap; std::map MapToPath; - + std::mutex Mutex; public: void RegisterResource(UUID uuid, const std::string& path) { + std::lock_guard lock(Mutex); // New resource is overwritting so we need to clear UUID -> Path map if (PathToMap.find(path) != PathToMap.end()) { @@ -32,6 +34,7 @@ namespace Nuake std::string GetResourcePath(UUID uuid) { + std::lock_guard lock(Mutex); if (MapToPath.find(uuid) != MapToPath.end()) { return MapToPath[uuid]; @@ -40,8 +43,14 @@ namespace Nuake return ""; } + void RemapResource(UUID oldUUID, UUID newUUID) + { + + } + UUID GetResourceUUID(const std::string& path) { + std::lock_guard lock(Mutex); if (PathToMap.find(path) != PathToMap.end()) { return PathToMap[path]; @@ -52,6 +61,7 @@ namespace Nuake void Serialize(const std::string& path) { + std::lock_guard lock(Mutex); json j; for (auto& [path, uuid] : PathToMap) { @@ -65,6 +75,7 @@ namespace Nuake void Deserialize(const std::string& path) { + std::lock_guard lock(Mutex); auto content = FileSystem::ReadFile(path); json j = json::parse(content); for (auto& [path, uuid] : j.items())