diff --git a/Flax.flaxproj b/Flax.flaxproj index 81a63a1fc..8b643ed8d 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -4,7 +4,7 @@ "Major": 1, "Minor": 7, "Revision": 1, - "Build": 6406 + "Build": 6407 }, "Company": "Flax", "Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.", diff --git a/Source/Editor/Cooker/PlatformTools.h b/Source/Editor/Cooker/PlatformTools.h index 533dad805..d7953cfd9 100644 --- a/Source/Editor/Cooker/PlatformTools.h +++ b/Source/Editor/Cooker/PlatformTools.h @@ -8,6 +8,37 @@ class TextureBase; +/// +/// The game cooker cache interface. +/// +class FLAXENGINE_API IBuildCache +{ +public: + /// + /// Removes all cached entries for assets that contain a given asset type. This forces rebuild for them. + /// + virtual void InvalidateCachePerType(const StringView& typeName) = 0; + + /// + /// Removes all cached entries for assets that contain a given asset type. This forces rebuild for them. + /// + template + FORCE_INLINE void InvalidateCachePerType() + { + InvalidateCachePerType(T::TypeName); + } + + /// + /// Removes all cached entries for assets that contain a shader. This forces rebuild for them. + /// + void InvalidateCacheShaders(); + + /// + /// Removes all cached entries for assets that contain a texture. This forces rebuild for them. + /// + void InvalidateCacheTextures(); +}; + /// /// The platform support tools base interface. /// @@ -76,6 +107,27 @@ public: virtual bool IsNativeCodeFile(CookingData& data, const String& file); public: + /// + /// Loads the build cache. Allows to invalidate any cached asset types based on the build settings for incremental builds (eg. invalidate textures/shaders). + /// + /// The cooking data. + /// The build cache interface. + /// The loaded cache data. Can be empty when starting a fresh build. + virtual void LoadCache(CookingData& data, IBuildCache* cache, const Span& bytes) + { + } + + /// + /// Saves the build cache. Allows to store any build settings to be used for cache invalidation on incremental builds. + /// + /// The cooking data. + /// The build cache interface. + /// Data to cache, will be restored during next incremental build. + virtual Array SaveCache(CookingData& data, IBuildCache* cache) + { + return Array(); + } + /// /// Called when game building starts. /// diff --git a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp index 8fd87bcfd..366a4faef 100644 --- a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp +++ b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp @@ -35,6 +35,7 @@ #include "Engine/Engine/Base/GameBase.h" #include "Engine/Engine/Globals.h" #include "Engine/Tools/TextureTool/TextureTool.h" +#include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Scripting/Enums.h" #if PLATFORM_TOOLS_WINDOWS #include "Engine/Platform/Windows/WindowsPlatformSettings.h" @@ -49,6 +50,20 @@ Dictionary CookAssetsStep::AssetProcessors; +void IBuildCache::InvalidateCacheShaders() +{ + InvalidateCachePerType(); + InvalidateCachePerType(); + InvalidateCachePerType(); +} + +void IBuildCache::InvalidateCacheTextures() +{ + InvalidateCachePerType(); + InvalidateCachePerType(); + InvalidateCachePerType(); +} + bool CookAssetsStep::CacheEntry::IsValid(bool withDependencies) { AssetInfo assetInfo; @@ -113,15 +128,13 @@ void CookAssetsStep::CacheData::InvalidateCachePerType(const StringView& typeNam void CookAssetsStep::CacheData::Load(CookingData& data) { + PROFILE_CPU(); HeaderFilePath = data.CacheDirectory / String::Format(TEXT("CookedHeader_{0}.bin"), FLAXENGINE_VERSION_BUILD); CacheFolder = data.CacheDirectory / TEXT("Cooked"); Entries.Clear(); if (!FileSystem::DirectoryExists(CacheFolder)) - { FileSystem::CreateDirectory(CacheFolder); - } - if (!FileSystem::FileExists(HeaderFilePath)) { LOG(Warning, "Missing incremental build cooking assets cache."); @@ -143,9 +156,7 @@ void CookAssetsStep::CacheData::Load(CookingData& data) return; LOG(Info, "Loading incremental build cooking cache (entries count: {0})", entriesCount); - file->ReadBytes(&Settings, sizeof(Settings)); - Entries.EnsureCapacity(Math::RoundUpToPowerOf2(static_cast(entriesCount * 3.0f))); Array> fileDependencies; @@ -179,6 +190,9 @@ void CookAssetsStep::CacheData::Load(CookingData& data) e.FileDependencies = fileDependencies; } + Array platformCache; + file->Read(platformCache); + int32 checkChar; file->ReadInt32(&checkChar); if (checkChar != 13) @@ -187,6 +201,9 @@ void CookAssetsStep::CacheData::Load(CookingData& data) Entries.Clear(); } + // Per-platform custom data loading (eg. to invalidate textures/shaders options) + data.Tools->LoadCache(data, this, ToSpan(platformCache)); + const auto buildSettings = BuildSettings::Get(); const auto gameSettings = GameSettings::Get(); @@ -200,12 +217,12 @@ void CookAssetsStep::CacheData::Load(CookingData& data) if (MATERIAL_GRAPH_VERSION != Settings.Global.MaterialGraphVersion) { LOG(Info, "{0} option has been modified.", TEXT("MaterialGraphVersion")); - InvalidateCachePerType(Material::TypeName); + InvalidateCachePerType(); } if (PARTICLE_GPU_GRAPH_VERSION != Settings.Global.ParticleGraphVersion) { LOG(Info, "{0} option has been modified.", TEXT("ParticleGraphVersion")); - InvalidateCachePerType(ParticleEmitter::TypeName); + InvalidateCachePerType(); } if (buildSettings->ShadersNoOptimize != Settings.Global.ShadersNoOptimize) { @@ -262,24 +279,24 @@ void CookAssetsStep::CacheData::Load(CookingData& data) #endif if (invalidateShaders) { - InvalidateCachePerType(Shader::TypeName); - InvalidateCachePerType(Material::TypeName); - InvalidateCachePerType(ParticleEmitter::TypeName); + InvalidateCachePerType(); + InvalidateCachePerType(); + InvalidateCachePerType(); } // Invalidate textures if streaming settings gets modified if (Settings.Global.StreamingSettingsAssetId != gameSettings->Streaming || (Entries.ContainsKey(gameSettings->Streaming) && !Entries[gameSettings->Streaming].IsValid())) { - InvalidateCachePerType(Texture::TypeName); - InvalidateCachePerType(CubeTexture::TypeName); - InvalidateCachePerType(SpriteAtlas::TypeName); + InvalidateCachePerType(); + InvalidateCachePerType(); + InvalidateCachePerType(); } } -void CookAssetsStep::CacheData::Save() +void CookAssetsStep::CacheData::Save(CookingData& data) { + PROFILE_CPU(); LOG(Info, "Saving incremental build cooking cache (entries count: {0})", Entries.Count()); - auto file = FileWriteStream::Open(HeaderFilePath); if (file == nullptr) return; @@ -302,6 +319,7 @@ void CookAssetsStep::CacheData::Save() file->Write(f.Second); } } + file->Write(data.Tools->SaveCache(data, this)); file->WriteInt32(13); } @@ -961,6 +979,7 @@ public: const int32 count = addedEntries.Count(); if (count == 0) return false; + PROFILE_CPU(); // Get assets init data and load all chunks Array assetsData; @@ -1143,7 +1162,7 @@ bool CookAssetsStep::Perform(CookingData& data) // Cook asset if (Process(data, cache, assetRef.Get())) { - cache.Save(); + cache.Save(data); return true; } data.Stats.CookedAssets++; @@ -1151,12 +1170,12 @@ bool CookAssetsStep::Perform(CookingData& data) // Auto save build cache after every few cooked assets (reduces next build time if cooking fails later) if (data.Stats.CookedAssets % 50 == 0) { - cache.Save(); + cache.Save(data); } } // Save build cache header - cache.Save(); + cache.Save(data); // Create build game header { @@ -1173,7 +1192,6 @@ bool CookAssetsStep::Perform(CookingData& data) } stream->WriteInt32(('x' + 'D') * 131); // think about it as '131 times xD' - stream->WriteInt32(FLAXENGINE_VERSION_BUILD); Array bytes; diff --git a/Source/Editor/Cooker/Steps/CookAssetsStep.h b/Source/Editor/Cooker/Steps/CookAssetsStep.h index c552e532c..ae6bf7a6f 100644 --- a/Source/Editor/Cooker/Steps/CookAssetsStep.h +++ b/Source/Editor/Cooker/Steps/CookAssetsStep.h @@ -3,6 +3,7 @@ #pragma once #include "Editor/Cooker/GameCooker.h" +#include "Editor/Cooker/PlatformTools.h" #include "Engine/Core/Types/Pair.h" #include "Engine/Core/Types/DateTime.h" #include "Engine/Core/Collections/Dictionary.h" @@ -56,7 +57,7 @@ public: /// /// Assets cooking cache data (incremental building feature). /// - struct FLAXENGINE_API CacheData + struct FLAXENGINE_API CacheData : public IBuildCache { /// /// The cache header file path. @@ -136,16 +137,6 @@ public: /// The added entry reference. CacheEntry& CreateEntry(const Asset* asset, String& cachedFilePath); - /// - /// Removes all cached entries for assets that contain a shader. This forces rebuild for them. - /// - void InvalidateShaders(); - - /// - /// Removes all cached entries for assets that contain a texture. This forces rebuild for them. - /// - void InvalidateCachePerType(const StringView& typeName); - /// /// Loads the cache for the given cooking data. /// @@ -155,7 +146,11 @@ public: /// /// Saves this cache (header file). /// - void Save(); + /// The data. + void Save(CookingData& data); + + using IBuildCache::InvalidateCachePerType; + void InvalidateCachePerType(const StringView& typeName) override; }; struct FLAXENGINE_API AssetCookData