Live reloading

This commit is contained in:
antopilo
2025-04-21 11:36:26 -04:00
parent ce89e8b466
commit 85062d4de5
12 changed files with 243 additions and 24 deletions

View File

@@ -73,6 +73,8 @@ void EditorLayer::OnUpdate()
Nuake::Engine::EndDraw();
Nuake::Input::Update();
RID::ExecuteRemaps();
}
void EditorLayer::OnDetach()

View File

@@ -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")
{

View File

@@ -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 <filesystem>
#include <Nuake/Resource/ResourceManifest.h>
#include <Nuake/Resource/ResourceManager.h>
#include "Nuake/Resource/RID.h"
using namespace Nuake;
@@ -113,8 +120,11 @@ std::vector<Ref<File>> FileSystem::GetAllFiles(const FileType fileType)
void FileSystem::SetRootDirectory(const std::string path)
{
Root = path;
RootFileWatch = CreateRef<filewatch::FileWatch<std::string>>(
path, [&](const std::string& path, const filewatch::Event& event)
if (!RootFileWatch)
{
RootFileWatch = CreateRef<filewatch::FileWatch<std::string>>(
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<File> newImportedFile = CreateRef<File>(parentDirectory, FileSystem::RelativeToAbsolute(normalizedPath), name, extension);
parentDirectory->Files.push_back(newImportedFile);
AssetBakerManager::Get().OnNewAssetDetected(newImportedFile);
}
if(Ref<File> file = GetFile(normalizedPath); file)
if (Ref<File> 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<File> 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();
}

View File

@@ -3,6 +3,7 @@
#include "FileTypes.h"
#include <functional>
#include <queue>
namespace filewatch
{
@@ -17,8 +18,15 @@ namespace Nuake
using OnFileFunc = std::function<void(Ref<File>)>;
struct FileProcessRequest
{
Ref<File> FileToProcess;
};
class FileSystem
{
private:
public:
static std::string Root;
static Ref<Directory> RootDirectory;

View File

@@ -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;

View File

@@ -34,6 +34,7 @@
#include "vk_mem_alloc.h"
#include <array>
#include <mutex>
#include <algorithm>
bool NKUseValidationLayer = false;
@@ -767,9 +768,11 @@ bool VkRenderer::Draw()
return true;
}
std::mutex queueMutex;
void VkRenderer::EndDraw()
{
std::lock_guard<std::mutex> lock(queueMutex);
if (FrameSkipped)
{
return;
@@ -856,8 +859,10 @@ void VkRenderer::DrawImgui(VkCommandBuffer cmd, VkImageView targetImageView)
vkCmdEndRendering(cmd);
}
void VkRenderer::ImmediateSubmit(std::function<void(VkCommandBuffer cmd)>&& function)
{
std::lock_guard<std::mutex> lock(queueMutex);
VK_CALL(vkResetFences(Device, 1, &ImguiFence));
VK_CALL(vkResetCommandBuffer(ImguiCommandBuffer, 0));

View File

@@ -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<VkDescriptorImageInfo> 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;

View File

@@ -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 <string>
#include <chrono>
#include <filesystem>
#include <map>
#include <string>
#include <thread>
namespace Nuake
{
@@ -29,13 +34,77 @@ namespace Nuake
}
}
void OnAssetReimport(const Ref<File>& 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>& 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<File> Bake(const Ref<File>& 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);

View File

@@ -1,4 +1,7 @@
#include "RID.h"
using namespace Nuake;
std::vector<RID*> RID::Handles;
std::queue<RID::RemapRequest> RID::RemapQueue;
std::mutex RID::RemapMutex;

View File

@@ -10,13 +10,73 @@ namespace Nuake
class RID
{
private:
struct RemapRequest
{
UUID Old;
UUID New;
};
static std::vector<RID*> Handles;
static std::queue<RemapRequest> RemapQueue;
static std::mutex RemapMutex;
public:
UUID ID;
Ref<Resource> 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<std::mutex> 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<std::mutex> lock(RemapMutex);
if (old == newUUID)
{
return;
}
RemapQueue.push({ old, newUUID });
}
public:
template<typename T>
Ref<T> Get()

View File

@@ -25,6 +25,11 @@ namespace Nuake
static ResourceManifest Manifest;
static Ref<Resource> GetResource(const UUID& uuid);
static void RemapResource(const UUID& oldUUID, const UUID& newUUID)
{
m_Resources[oldUUID] = m_Resources[newUUID];
}
static void RegisterResource(Ref<Resource> 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<Resource> RegisterUnregisteredRessource(Ref<File> file)
{
Ref<Resource> resolvedResource = ResourceResolverManager::Get().Resolve(file);

View File

@@ -5,6 +5,7 @@
#include "Nuake/FileSystem/FileSystem.h"
#include <map>
#include <mutex>
#include <string>
namespace Nuake
@@ -16,10 +17,11 @@ namespace Nuake
private:
std::map<std::string, UUID> PathToMap;
std::map<UUID, std::string> MapToPath;
std::mutex Mutex;
public:
void RegisterResource(UUID uuid, const std::string& path)
{
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> lock(Mutex);
json j;
for (auto& [path, uuid] : PathToMap)
{
@@ -65,6 +75,7 @@ namespace Nuake
void Deserialize(const std::string& path)
{
std::lock_guard<std::mutex> lock(Mutex);
auto content = FileSystem::ReadFile(path);
json j = json::parse(content);
for (auto& [path, uuid] : j.items())