diff --git a/Source/Editor/Windows/Profiler/Memory.cs b/Source/Editor/Windows/Profiler/Memory.cs index 806bed18f..6958b828b 100644 --- a/Source/Editor/Windows/Profiler/Memory.cs +++ b/Source/Editor/Windows/Profiler/Memory.cs @@ -232,7 +232,7 @@ namespace FlaxEditor.Windows.Profiler Array.Sort(_groupOrder, (x, y) => { var tmp = _frames.Get(selectedFrame); - return (int)(tmp.Usage.Values0[y] - tmp.Usage.Values0[x]); + return tmp.Usage.Values0[y].CompareTo(tmp.Usage.Values0[x]); }); // Add rows diff --git a/Source/Engine/Foliage/Foliage.cpp b/Source/Engine/Foliage/Foliage.cpp index a1cd046ae..29771c29c 100644 --- a/Source/Engine/Foliage/Foliage.cpp +++ b/Source/Engine/Foliage/Foliage.cpp @@ -400,6 +400,7 @@ void Foliage::DrawClusterGlobalSA(GlobalSurfaceAtlasPass* globalSA, const Vector void Foliage::DrawFoliageJob(int32 i) { PROFILE_CPU(); + PROFILE_MEM(Graphics); const FoliageType& type = FoliageTypes[i]; if (type.IsReady() && type.Model->CanBeRendered()) { @@ -551,6 +552,7 @@ FoliageType* Foliage::GetFoliageType(int32 index) void Foliage::AddFoliageType(Model* model) { PROFILE_CPU(); + PROFILE_MEM(LevelFoliage); // Ensure to have unique model CHECK(model); @@ -629,6 +631,7 @@ int32 Foliage::GetFoliageTypeInstancesCount(int32 index) const void Foliage::AddInstance(const FoliageInstance& instance) { + PROFILE_MEM(LevelFoliage); ASSERT(instance.Type >= 0 && instance.Type < FoliageTypes.Count()); auto type = &FoliageTypes[instance.Type]; @@ -705,6 +708,7 @@ void Foliage::OnFoliageTypeModelLoaded(int32 index) if (_disableFoliageTypeEvents) return; PROFILE_CPU(); + PROFILE_MEM(LevelFoliage); auto& type = FoliageTypes[index]; ASSERT(type.IsReady()); @@ -803,6 +807,7 @@ void Foliage::OnFoliageTypeModelLoaded(int32 index) void Foliage::RebuildClusters() { PROFILE_CPU(); + PROFILE_MEM(LevelFoliage); // Faster path if foliage is empty or no types is ready bool anyTypeReady = false; @@ -1328,6 +1333,7 @@ void Foliage::Deserialize(DeserializeStream& stream, ISerializeModifier* modifie Actor::Deserialize(stream, modifier); PROFILE_CPU(); + PROFILE_MEM(LevelFoliage); // Clear #if FOLIAGE_USE_SINGLE_QUAD_TREE diff --git a/Source/Engine/Foliage/FoliageType.cpp b/Source/Engine/Foliage/FoliageType.cpp index 0f1893e67..8b8c84420 100644 --- a/Source/Engine/Foliage/FoliageType.cpp +++ b/Source/Engine/Foliage/FoliageType.cpp @@ -4,6 +4,7 @@ #include "Engine/Core/Collections/ArrayExtensions.h" #include "Engine/Core/Random.h" #include "Engine/Serialization/Serialization.h" +#include "Engine/Profiler/ProfilerMemory.h" #include "Foliage.h" FoliageType::FoliageType() @@ -62,6 +63,7 @@ Array FoliageType::GetMaterials() const void FoliageType::SetMaterials(const Array& value) { + PROFILE_MEM(LevelFoliage); CHECK(value.Count() == Entries.Count()); for (int32 i = 0; i < value.Count(); i++) Entries[i].Material = value[i]; @@ -114,6 +116,8 @@ void FoliageType::OnModelChanged() void FoliageType::OnModelLoaded() { + PROFILE_MEM(LevelFoliage); + // Now it's ready _isReady = 1; @@ -169,6 +173,7 @@ void FoliageType::Serialize(SerializeStream& stream, const void* otherObj) void FoliageType::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) { + PROFILE_MEM(LevelFoliage); DESERIALIZE(Model); const auto member = stream.FindMember("Materials"); diff --git a/Source/Engine/Profiler/ProfilerMemory.cpp b/Source/Engine/Profiler/ProfilerMemory.cpp index 49cc9649f..d53e48b17 100644 --- a/Source/Engine/Profiler/ProfilerMemory.cpp +++ b/Source/Engine/Profiler/ProfilerMemory.cpp @@ -21,6 +21,7 @@ #define USE_TRACY_MEMORY_PLOTS (defined(TRACY_ENABLE)) static_assert(GROUPS_COUNT <= MAX_uint8, "Fix memory profiler groups to fit a single byte."); +static_assert(sizeof(ProfilerMemory::Groups) == sizeof(uint8), "Fix memory profiler groups to fit a single byte."); // Compact name storage. struct GroupNameBuffer @@ -32,17 +33,17 @@ struct GroupNameBuffer void Set(const T* str, bool autoFormat = false) { int32 max = StringUtils::Length(str), dst = 0; - char prev = 0; + T prev = 0; for (int32 i = 0; i < max && dst < ARRAY_COUNT(Buffer) - 2; i++) { - char cur = (char)str[i]; + T cur = (T)str[i]; if (autoFormat && StringUtils::IsUpper(cur) && StringUtils::IsLower(prev)) { Ansi[dst] = '/'; Buffer[dst++] = '/'; } - Ansi[dst] = cur; - Buffer[dst++] = cur; + Ansi[dst] = (char)cur; + Buffer[dst++] = (Char)cur; prev = cur; } Buffer[dst] = 0; @@ -257,6 +258,8 @@ void InitProfilerMemory(const Char* cmdLine, int32 stage) INIT_PARENT(Animations, AnimationsData); INIT_PARENT(Content, ContentAssets); INIT_PARENT(Content, ContentFiles); + INIT_PARENT(Level, LevelFoliage); + INIT_PARENT(Level, LevelTerrain); INIT_PARENT(Scripting, ScriptingVisual); INIT_PARENT(Scripting, ScriptingCSharp); INIT_PARENT(ScriptingCSharp, ScriptingCSharpGCCommitted); @@ -403,10 +406,10 @@ ProfilerMemory::GroupsArray ProfilerMemory::GetGroups(int32 mode) void ProfilerMemory::Dump(const StringView& options) { #if LOG_ENABLE - bool file = options.Contains(TEXT("file")); + bool file = options.Contains(TEXT("file"), StringSearchCase::IgnoreCase); StringBuilder output; int32 maxCount = 20; - if (file || options.Contains(TEXT("all"))) + if (file || options.Contains(TEXT("all"), StringSearchCase::IgnoreCase)) maxCount = MAX_int32; ::Dump(output, maxCount); if (file) @@ -476,10 +479,10 @@ void ProfilerMemory::OnMemoryFree(void* ptr) stack.SkipRecursion = false; } -void ProfilerMemory::OnGroupUpdate(Groups group, int64 sizeDelta, int64 countDetla) +void ProfilerMemory::OnGroupUpdate(Groups group, int64 sizeDelta, int64 countDelta) { Platform::InterlockedAdd(&GroupMemory[(int32)group], sizeDelta); - Platform::InterlockedAdd(&GroupMemoryCount[(int32)group], countDetla); + Platform::InterlockedAdd(&GroupMemoryCount[(int32)group], countDelta); UPDATE_PEEK(group); } diff --git a/Source/Engine/Profiler/ProfilerMemory.h b/Source/Engine/Profiler/ProfilerMemory.h index 2112a407d..e42b8720e 100644 --- a/Source/Engine/Profiler/ProfilerMemory.h +++ b/Source/Engine/Profiler/ProfilerMemory.h @@ -61,7 +61,7 @@ public: GraphicsVertexBuffers, // Total index buffers memory usage. GraphicsIndexBuffers, - // Total meshes memory usage (vertex and idnex buffers allocated by models). + // Total meshes memory usage (vertex and index buffers allocated by models). GraphicsMeshes, // Totoal shaders memory usage (shaders bytecode, PSOs data). GraphicsShaders, @@ -78,7 +78,7 @@ public: // Total animation data memory usage (curves, events, keyframes, graphs, etc.). AnimationsData, - // Total autio system memory. + // Total audio system memory. Audio, // Total content system memory usage. @@ -90,11 +90,15 @@ public: // Total memory used by content streaming system (internals). ContentStreaming, - // Total memory allocated by input system. - Input, - // Total memory allocated by scene objects. Level, + // Total memory allocated by the foliage system (quad-tree, foliage instances data). Excluding foliage models data. + LevelFoliage, + // Total memory allocated by the terrain system (patches). + LevelTerrain, + + // Total memory allocated by input system. + Input, // Total localization system memory. Localization, @@ -148,7 +152,7 @@ public: CustomGame8, // Custom game-specific memory tracking. CustomGame9, - + // Custom plugin-specific memory tracking. CustomPlugin0, // Custom plugin-specific memory tracking. @@ -186,7 +190,7 @@ public: }; /// - /// The memory groups array wraper to avoid dynamic memory allocation. + /// The memory groups array wrapper to avoid dynamic memory allocation. /// API_STRUCT(NoDefault) struct GroupsArray { @@ -254,7 +258,7 @@ public: static void OnMemoryAlloc(void* ptr, uint64 size); static void OnMemoryFree(void* ptr); - static void OnGroupUpdate(Groups group, int64 sizeDelta, int64 countDetla); + static void OnGroupUpdate(Groups group, int64 sizeDelta, int64 countDelta); public: /// diff --git a/Source/Engine/Terrain/Terrain.cpp b/Source/Engine/Terrain/Terrain.cpp index ebbfd70e6..85274b8fb 100644 --- a/Source/Engine/Terrain/Terrain.cpp +++ b/Source/Engine/Terrain/Terrain.cpp @@ -16,6 +16,7 @@ #include "Engine/Graphics/Textures/GPUTexture.h" #include "Engine/Level/Scene/Scene.h" #include "Engine/Profiler/ProfilerCPU.h" +#include "Engine/Profiler/ProfilerMemory.h" #include "Engine/Renderer/GlobalSignDistanceFieldPass.h" #include "Engine/Renderer/GI/GlobalSurfaceAtlasPass.h" @@ -290,6 +291,7 @@ void Terrain::SetCollisionLOD(int32 value) void Terrain::SetPhysicalMaterials(const Array, FixedAllocation<8>>& value) { + PROFILE_MEM(LevelTerrain); _physicalMaterials = value; _physicalMaterials.Resize(8); JsonAsset* materials[8]; @@ -431,6 +433,7 @@ void Terrain::Setup(int32 lodCount, int32 chunkSize) void Terrain::AddPatches(const Int2& numberOfPatches) { + PROFILE_MEM(LevelTerrain); if (_chunkSize == 0) Setup(); _patches.ClearDelete(); @@ -470,6 +473,7 @@ void Terrain::AddPatch(const Int2& patchCoord) LOG(Warning, "Cannot add patch at {0}x{1}. The patch at the given location already exists.", patchCoord.X, patchCoord.Y); return; } + PROFILE_MEM(LevelTerrain); if (_chunkSize == 0) Setup(); @@ -726,6 +730,8 @@ void Terrain::Serialize(SerializeStream& stream, const void* otherObj) void Terrain::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) { + PROFILE_MEM(LevelTerrain); + // Base Actor::Deserialize(stream, modifier); diff --git a/Source/Engine/Terrain/TerrainManager.cpp b/Source/Engine/Terrain/TerrainManager.cpp index 594cdd39b..6da020079 100644 --- a/Source/Engine/Terrain/TerrainManager.cpp +++ b/Source/Engine/Terrain/TerrainManager.cpp @@ -5,16 +5,17 @@ #include "Engine/Threading/Threading.h" #include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/GPUBuffer.h" +#include "Engine/Graphics/Shaders/GPUVertexLayout.h" +#include "Engine/Core/Log.h" #include "Engine/Core/Math/Color32.h" #include "Engine/Core/Collections/ChunkedArray.h" #include "Engine/Core/Collections/Dictionary.h" -#include "Engine/Content/Content.h" #include "Engine/Engine/EngineService.h" +#include "Engine/Content/Content.h" #include "Engine/Content/Assets/MaterialBase.h" #include "Engine/Content/AssetReference.h" -#include "Engine/Core/Log.h" -#include "Engine/Graphics/Shaders/GPUVertexLayout.h" #include "Engine/Renderer/DrawCall.h" +#include "Engine/Profiler/ProfilerMemory.h" // Must match structure defined in Terrain.shader struct TerrainVertex @@ -94,6 +95,7 @@ bool TerrainManager::GetChunkGeometry(DrawCall& drawCall, int32 chunkSize, int32 data->GetChunkGeometry(drawCall); return false; } + PROFILE_MEM(LevelTerrain); // Prepare const int32 vertexCount = (chunkSize + 1) >> lodIndex; diff --git a/Source/Engine/Terrain/TerrainPatch.cpp b/Source/Engine/Terrain/TerrainPatch.cpp index 1c754d843..65cdace25 100644 --- a/Source/Engine/Terrain/TerrainPatch.cpp +++ b/Source/Engine/Terrain/TerrainPatch.cpp @@ -6,6 +6,7 @@ #include "Engine/Core/Log.h" #include "Engine/Core/Math/Color32.h" #include "Engine/Profiler/ProfilerCPU.h" +#include "Engine/Profiler/ProfilerMemory.h" #include "Engine/Physics/Physics.h" #include "Engine/Physics/PhysicsScene.h" #include "Engine/Physics/PhysicsBackend.h" @@ -66,6 +67,7 @@ TerrainPatch::TerrainPatch(const SpawnParams& params) void TerrainPatch::Init(Terrain* terrain, int16 x, int16 z) { + PROFILE_MEM(LevelTerrain); ScopeLock lock(_collisionLocker); _terrain = terrain; @@ -823,6 +825,7 @@ bool ModifyCollision(TerrainDataUpdateInfo& info, TextureBase::InitData* initDat bool TerrainPatch::SetupHeightMap(int32 heightMapLength, const float* heightMap, const byte* holesMask, bool forceUseVirtualStorage) { PROFILE_CPU_NAMED("Terrain.Setup"); + PROFILE_MEM(LevelTerrain); if (heightMap == nullptr) { LOG(Warning, "Cannot create terrain without a heightmap specified."); @@ -1034,6 +1037,7 @@ bool TerrainPatch::SetupHeightMap(int32 heightMapLength, const float* heightMap, bool TerrainPatch::SetupSplatMap(int32 index, int32 splatMapLength, const Color32* splatMap, bool forceUseVirtualStorage) { PROFILE_CPU_NAMED("Terrain.SetupSplatMap"); + PROFILE_MEM(LevelTerrain); CHECK_RETURN(index >= 0 && index < TERRAIN_MAX_SPLATMAPS_COUNT, true); if (splatMap == nullptr) { @@ -1182,6 +1186,7 @@ bool TerrainPatch::SetupSplatMap(int32 index, int32 splatMapLength, const Color3 bool TerrainPatch::InitializeHeightMap() { PROFILE_CPU_NAMED("Terrain.InitializeHeightMap"); + PROFILE_MEM(LevelTerrain); const auto heightmapSize = _terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1; Array heightmap; heightmap.Resize(heightmapSize * heightmapSize); @@ -1248,6 +1253,7 @@ void TerrainPatch::ClearCache() void TerrainPatch::CacheHeightData() { PROFILE_CPU_NAMED("Terrain.CacheHeightData"); + PROFILE_MEM(LevelTerrain); const TerrainDataUpdateInfo info(this); // Ensure that heightmap data is all loaded @@ -1313,6 +1319,7 @@ void TerrainPatch::CacheHeightData() void TerrainPatch::CacheSplatData() { PROFILE_CPU_NAMED("Terrain.CacheSplatData"); + PROFILE_MEM(LevelTerrain); const TerrainDataUpdateInfo info(this); // Cache all the splatmaps @@ -1396,6 +1403,7 @@ bool TerrainPatch::ModifyHeightMap(const float* samples, const Int2& modifiedOff return true; } PROFILE_CPU_NAMED("Terrain.ModifyHeightMap"); + PROFILE_MEM(LevelTerrain); // Check if has no heightmap if (Heightmap == nullptr) @@ -1490,6 +1498,7 @@ bool TerrainPatch::ModifyHolesMask(const byte* samples, const Int2& modifiedOffs return true; } PROFILE_CPU_NAMED("Terrain.ModifyHolesMask"); + PROFILE_MEM(LevelTerrain); // Check if has no heightmap if (Heightmap == nullptr) @@ -1567,6 +1576,7 @@ bool TerrainPatch::ModifySplatMap(int32 index, const Color32* samples, const Int return true; } PROFILE_CPU_NAMED("Terrain.ModifySplatMap"); + PROFILE_MEM(LevelTerrain); // Get the current data to modify it Color32* splatMap = GetSplatMapData(index); @@ -1738,6 +1748,7 @@ bool TerrainPatch::ModifySplatMap(int32 index, const Color32* samples, const Int bool TerrainPatch::UpdateHeightData(TerrainDataUpdateInfo& info, const Int2& modifiedOffset, const Int2& modifiedSize, bool wasHeightRangeChanged, bool wasHeightChanged) { PROFILE_CPU(); + PROFILE_MEM(LevelTerrain); float* heightMap = GetHeightmapData(); byte* holesMask = GetHolesMaskData(); ASSERT(heightMap && holesMask); @@ -2126,6 +2137,7 @@ void TerrainPatch::UpdatePostManualDeserialization() void TerrainPatch::CreateCollision() { PROFILE_CPU(); + PROFILE_MEM(LevelTerrain); ASSERT(!HasCollision()); if (CreateHeightField()) return; @@ -2241,6 +2253,7 @@ void TerrainPatch::DestroyCollision() void TerrainPatch::CacheDebugLines() { PROFILE_CPU(); + PROFILE_MEM(LevelTerrain); ASSERT(_physicsHeightField); _debugLinesDirty = false; if (!_debugLines) @@ -2322,6 +2335,7 @@ void TerrainPatch::DrawPhysicsDebug(RenderView& view) const BoundingBox bounds(_bounds.Minimum - view.Origin, _bounds.Maximum - view.Origin); if (!_physicsShape || !view.CullingFrustum.Intersects(bounds)) return; + PROFILE_MEM(LevelTerrain); if (view.Mode == ViewMode::PhysicsColliders) { const auto& triangles = GetCollisionTriangles(); @@ -2378,6 +2392,7 @@ const Array& TerrainPatch::GetCollisionTriangles() if (!_physicsShape || _collisionTriangles.HasItems()) return _collisionTriangles; PROFILE_CPU(); + PROFILE_MEM(LevelTerrain); int32 rows, cols; PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols); @@ -2428,6 +2443,7 @@ const Array& TerrainPatch::GetCollisionTriangles() void TerrainPatch::GetCollisionTriangles(const BoundingSphere& bounds, Array& result) { PROFILE_CPU(); + PROFILE_MEM(LevelTerrain); result.Clear(); // Skip if no intersection with patch @@ -2525,6 +2541,7 @@ void TerrainPatch::GetCollisionTriangles(const BoundingSphere& bounds, Array& vertexBuffer, Array& indexBuffer) { PROFILE_CPU(); + PROFILE_MEM(LevelTerrain); vertexBuffer.Clear(); indexBuffer.Clear();