< Summary

Class:DCL.SceneMetricsController
Assembly:MainScripts
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/WorldRuntime/SceneMetricsController.cs
Covered lines:146
Uncovered lines:19
Coverable lines:165
Total lines:374
Line coverage:88.4% (146 of 165)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
EntityMetrics()0%110100%
ToString()0%2100%
GetModel()0%110100%
SceneMetricsController(...)0%2.012088.89%
Enable()0%2.012085.71%
Disable()0%2.032080%
GetLimits()0%220100%
IsInsideTheLimits()0%8.817066.67%
SendEvent()0%220100%
OnEntityAdded(...)0%110100%
OnEntityRemoved(...)0%110100%
OnEntityMeshInfoUpdated(...)0%110100%
OnEntityMeshInfoCleaned(...)0%110100%
AddOrReplaceMetrics(...)0%220100%
SubstractMetrics(...)0%330100%
AddMetrics(...)0%9.319084.38%
CalculateMaterials(...)0%4.014090.91%
AddMesh(...)0%3.13077.78%
RemoveEntityMeshes(...)0%440100%
AddMaterial(...)0%4.014090.91%
RemoveEntitiesMaterial(...)0%440100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/WorldRuntime/SceneMetricsController.cs

#LineLine coverage
 1using DCL.Controllers;
 2using DCL.Interface;
 3using DCL.Models;
 4using System.Collections.Generic;
 5using UnityEngine;
 6
 7namespace DCL
 8{
 9    [System.Serializable]
 10    public class SceneMetricsController : ISceneMetricsController
 11    {
 12        private static bool VERBOSE = false;
 13        public IParcelScene scene;
 14
 15        public static class LimitsConfig
 16        {
 17            // number of entities
 18            public const int entities = 200;
 19
 20            // Number of faces (per parcel)
 21            public const int triangles = 10000;
 22            public const int bodies = 300;
 23            public const int textures = 10;
 24            public const int materials = 20;
 25            public const int meshes = 200;
 26
 27            public const float height = 20;
 28            public const float visibleRadius = 10;
 29        }
 30
 31        protected class EntityMetrics
 32        {
 47733            public Dictionary<Material, int> materials = new Dictionary<Material, int>();
 47734            public Dictionary<Mesh, int> meshes = new Dictionary<Mesh, int>();
 35            public int bodies = 0;
 36            public int triangles = 0;
 37            public int textures = 0;
 38
 39            override public string ToString()
 40            {
 041                return string.Format("materials: {0}, meshes: {1}, bodies: {2}, triangles: {3}, textures: {4}",
 42                    materials.Count, meshes.Count, bodies, triangles, textures);
 43            }
 44        }
 45
 46        [SerializeField]
 47        protected SceneMetricsModel model;
 48
 49        protected Dictionary<IDCLEntity, EntityMetrics> entitiesMetrics;
 50        private Dictionary<Mesh, int> uniqueMeshesRefCount;
 51        private Dictionary<Material, int> uniqueMaterialsRefCount;
 52
 053        public bool isDirty { get; protected set; }
 54
 1155        public SceneMetricsModel GetModel() { return model.Clone(); }
 56
 56157        public SceneMetricsController(IParcelScene sceneOwner)
 58        {
 56159            this.scene = sceneOwner;
 60
 56161            uniqueMeshesRefCount = new Dictionary<Mesh, int>();
 56162            uniqueMaterialsRefCount = new Dictionary<Material, int>();
 56163            entitiesMetrics = new Dictionary<IDCLEntity, EntityMetrics>();
 56164            model = new SceneMetricsModel();
 65
 56166            if (VERBOSE)
 67            {
 068                Debug.Log("Start ScenePerformanceLimitsController...");
 69            }
 56170        }
 71
 72        public void Enable()
 73        {
 56174            if (scene == null)
 075                return;
 76
 56177            scene.OnEntityAdded -= OnEntityAdded;
 56178            scene.OnEntityRemoved -= OnEntityRemoved;
 56179            scene.OnEntityAdded += OnEntityAdded;
 56180            scene.OnEntityRemoved += OnEntityRemoved;
 56181        }
 82
 83        public void Disable()
 84        {
 55985            if (scene == null)
 086                return;
 87
 55988            scene.OnEntityAdded -= OnEntityAdded;
 55989            scene.OnEntityRemoved -= OnEntityRemoved;
 55990        }
 91
 92        SceneMetricsModel cachedModel = null;
 93
 94        public SceneMetricsModel GetLimits()
 95        {
 142496            if (cachedModel == null)
 97            {
 53098                cachedModel = new SceneMetricsModel();
 99
 530100                int parcelCount = scene.sceneData.parcels.Length;
 530101                float log = Mathf.Log(parcelCount + 1, 2);
 530102                float lineal = parcelCount;
 103
 530104                cachedModel.triangles = (int) (lineal * LimitsConfig.triangles);
 530105                cachedModel.bodies = (int) (lineal * LimitsConfig.bodies);
 530106                cachedModel.entities = (int) (lineal * LimitsConfig.entities);
 530107                cachedModel.materials = (int) (log * LimitsConfig.materials);
 530108                cachedModel.textures = (int) (log * LimitsConfig.textures);
 530109                cachedModel.meshes = (int) (log * LimitsConfig.meshes);
 530110                cachedModel.sceneHeight = (int) (log * LimitsConfig.height);
 111            }
 112
 1424113            return cachedModel;
 114        }
 115
 116        public bool IsInsideTheLimits()
 117        {
 3118            SceneMetricsModel limits = GetLimits();
 3119            SceneMetricsModel usage = GetModel();
 120
 3121            if (usage.triangles > limits.triangles)
 0122                return false;
 123
 3124            if (usage.bodies > limits.bodies)
 0125                return false;
 126
 3127            if (usage.entities > limits.entities)
 1128                return false;
 129
 2130            if (usage.materials > limits.materials)
 0131                return false;
 132
 2133            if (usage.textures > limits.textures)
 0134                return false;
 135
 2136            if (usage.meshes > limits.meshes)
 0137                return false;
 138
 2139            return true;
 140        }
 141
 142        public void SendEvent()
 143        {
 587144            if (isDirty)
 145            {
 97146                isDirty = false;
 147
 97148                Interface.WebInterface.ReportOnMetricsUpdate(scene.sceneData.id,
 149                    model.ToMetricsModel(), GetLimits().ToMetricsModel());
 150            }
 587151        }
 152
 153        protected virtual void OnEntityAdded(IDCLEntity e)
 154        {
 470155            e.OnMeshesInfoUpdated += OnEntityMeshInfoUpdated;
 470156            e.OnMeshesInfoCleaned += OnEntityMeshInfoCleaned;
 470157            model.entities++;
 470158            isDirty = true;
 470159        }
 160
 161        protected virtual void OnEntityRemoved(IDCLEntity e)
 162        {
 29163            SubstractMetrics(e);
 29164            e.OnMeshesInfoUpdated -= OnEntityMeshInfoUpdated;
 29165            e.OnMeshesInfoCleaned -= OnEntityMeshInfoCleaned;
 29166            model.entities--;
 29167            isDirty = true;
 29168        }
 169
 954170        protected virtual void OnEntityMeshInfoUpdated(IDCLEntity entity) { AddOrReplaceMetrics(entity); }
 171
 376172        protected virtual void OnEntityMeshInfoCleaned(IDCLEntity entity) { SubstractMetrics(entity); }
 173
 174        protected void AddOrReplaceMetrics(IDCLEntity entity)
 175        {
 479176            if (entitiesMetrics.ContainsKey(entity))
 177            {
 262178                SubstractMetrics(entity);
 179            }
 180
 479181            AddMetrics(entity);
 479182        }
 183
 184        protected void SubstractMetrics(IDCLEntity entity)
 185        {
 480186            if (!entitiesMetrics.ContainsKey(entity))
 187            {
 14188                return;
 189            }
 190
 466191            EntityMetrics entityMetrics = entitiesMetrics[entity];
 192
 466193            RemoveEntitiesMaterial(entityMetrics);
 466194            RemoveEntityMeshes(entityMetrics);
 195
 466196            model.materials = uniqueMaterialsRefCount.Count;
 466197            model.meshes = uniqueMeshesRefCount.Count;
 466198            model.triangles -= entityMetrics.triangles;
 466199            model.bodies -= entityMetrics.bodies;
 200
 466201            if (entitiesMetrics.ContainsKey(entity))
 202            {
 466203                entitiesMetrics.Remove(entity);
 204            }
 205
 466206            isDirty = true;
 466207        }
 208
 209        protected void AddMetrics(IDCLEntity entity)
 210        {
 479211            if (entity.meshRootGameObject == null)
 212            {
 0213                return;
 214            }
 215
 216            // If the mesh is being loaded we should skip the evaluation (it will be triggered again later when the load
 479217            if (entity.meshRootGameObject.GetComponent<MaterialTransitionController>()) // the object's MaterialTransiti
 218            {
 2219                return;
 220            }
 221
 477222            EntityMetrics entityMetrics = new EntityMetrics();
 223
 477224            int visualMeshRawTriangles = 0;
 225
 226            //NOTE(Brian): If this proves to be too slow we can spread it with a Coroutine spooler.
 477227            MeshFilter[] meshFilters = entity.meshesInfo.meshFilters;
 228
 1624229            for (int i = 0; i < meshFilters.Length; i++)
 230            {
 335231                MeshFilter mf = meshFilters[i];
 232
 335233                if (mf != null && mf.sharedMesh != null)
 234                {
 335235                    visualMeshRawTriangles += mf.sharedMesh.triangles.Length;
 335236                    AddMesh(entityMetrics, mf.sharedMesh);
 335237                    if (VERBOSE)
 238                    {
 0239                        Debug.Log("SceneMetrics: tris count " + mf.sharedMesh.triangles.Length + " from mesh " + mf.shar
 0240                        Debug.Log("SceneMetrics: mesh " + mf.sharedMesh.name + " of entity " + entity.entityId);
 241                    }
 242                }
 243            }
 244
 477245            CalculateMaterials(entity, entityMetrics);
 246
 247            //The array is a list of triangles that contains indices into the vertex array. The size of the triangle arr
 248            //Vertices can be shared by simply indexing into the same vertex.
 477249            entityMetrics.triangles = visualMeshRawTriangles / 3;
 477250            entityMetrics.bodies = entity.meshesInfo.meshFilters.Length;
 251
 477252            model.materials = uniqueMaterialsRefCount.Count;
 477253            model.meshes = uniqueMeshesRefCount.Count;
 477254            model.triangles += entityMetrics.triangles;
 477255            model.bodies += entityMetrics.bodies;
 256
 477257            if (!entitiesMetrics.ContainsKey(entity))
 258            {
 477259                entitiesMetrics.Add(entity, entityMetrics);
 477260            }
 261            else
 262            {
 0263                entitiesMetrics[entity] = entityMetrics;
 264            }
 265
 477266            if (VERBOSE)
 267            {
 0268                Debug.Log("SceneMetrics: entity " + entity.entityId + " metrics " + entityMetrics.ToString());
 269            }
 270
 477271            isDirty = true;
 477272        }
 273
 274        void CalculateMaterials(IDCLEntity entity, EntityMetrics entityMetrics)
 275        {
 477276            var originalMaterials = Environment.i.world.sceneBoundsChecker.GetOriginalMaterials(entity.meshesInfo);
 477277            if (originalMaterials == null)
 17278                return;
 279
 460280            int originalMaterialsCount = originalMaterials.Count;
 281
 1546282            for (int i = 0; i < originalMaterialsCount; i++)
 283            {
 313284                AddMaterial(entityMetrics, originalMaterials[i]);
 285
 313286                if (VERBOSE)
 0287                    Debug.Log($"SceneMetrics: material (style: {Environment.i.world.sceneBoundsChecker.GetFeedbackStyle(
 288            }
 460289        }
 290
 291        void AddMesh(EntityMetrics entityMetrics, Mesh mesh)
 292        {
 335293            if (!uniqueMeshesRefCount.ContainsKey(mesh))
 294            {
 278295                uniqueMeshesRefCount.Add(mesh, 1);
 278296            }
 297            else
 298            {
 57299                uniqueMeshesRefCount[mesh] += 1;
 300            }
 301
 335302            if (!entityMetrics.meshes.ContainsKey(mesh))
 303            {
 335304                entityMetrics.meshes.Add(mesh, 1);
 335305            }
 306            else
 307            {
 0308                entityMetrics.meshes[mesh] += 1;
 309            }
 0310        }
 311
 312        void RemoveEntityMeshes(EntityMetrics entityMetrics)
 313        {
 466314            var entityMeshes = entityMetrics.meshes;
 466315            using (var iterator = entityMeshes.GetEnumerator())
 316            {
 788317                while (iterator.MoveNext())
 318                {
 322319                    if (uniqueMeshesRefCount.ContainsKey(iterator.Current.Key))
 320                    {
 322321                        uniqueMeshesRefCount[iterator.Current.Key] -= iterator.Current.Value;
 322322                        if (uniqueMeshesRefCount[iterator.Current.Key] <= 0)
 323                        {
 265324                            uniqueMeshesRefCount.Remove(iterator.Current.Key);
 325                        }
 326                    }
 327                }
 466328            }
 466329        }
 330
 331        void AddMaterial(EntityMetrics entityMetrics, Material material)
 332        {
 313333            if (material == null)
 0334                return;
 335
 313336            if (!uniqueMaterialsRefCount.ContainsKey(material))
 337            {
 236338                uniqueMaterialsRefCount.Add(material, 1);
 236339            }
 340            else
 341            {
 77342                uniqueMaterialsRefCount[material] += 1;
 343            }
 344
 313345            if (!entityMetrics.materials.ContainsKey(material))
 346            {
 295347                entityMetrics.materials.Add(material, 1);
 295348            }
 349            else
 350            {
 18351                entityMetrics.materials[material] += 1;
 352            }
 18353        }
 354
 355        void RemoveEntitiesMaterial(EntityMetrics entityMetrics)
 356        {
 466357            var entityMaterials = entityMetrics.materials;
 466358            using (var iterator = entityMaterials.GetEnumerator())
 359            {
 756360                while (iterator.MoveNext())
 361                {
 290362                    if (uniqueMaterialsRefCount.ContainsKey(iterator.Current.Key))
 363                    {
 290364                        uniqueMaterialsRefCount[iterator.Current.Key] -= iterator.Current.Value;
 290365                        if (uniqueMaterialsRefCount[iterator.Current.Key] <= 0)
 366                        {
 231367                            uniqueMaterialsRefCount.Remove(iterator.Current.Key);
 368                        }
 369                    }
 370                }
 466371            }
 466372        }
 373    }
 374}