< Summary

Class:DCL.SceneMetricsController
Assembly:MainScripts
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/WorldRuntime/SceneMetricsController.cs
Covered lines:148
Uncovered lines:17
Coverable lines:165
Total lines:374
Line coverage:89.6% (148 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%330100%
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        {
 53833            public Dictionary<Material, int> materials = new Dictionary<Material, int>();
 53834            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
 2755        public SceneMetricsModel GetModel() { return model.Clone(); }
 56
 72957        public SceneMetricsController(IParcelScene sceneOwner)
 58        {
 72959            this.scene = sceneOwner;
 60
 72961            uniqueMeshesRefCount = new Dictionary<Mesh, int>();
 72962            uniqueMaterialsRefCount = new Dictionary<Material, int>();
 72963            entitiesMetrics = new Dictionary<IDCLEntity, EntityMetrics>();
 72964            model = new SceneMetricsModel();
 65
 72966            if (VERBOSE)
 67            {
 068                Debug.Log("Start ScenePerformanceLimitsController...");
 69            }
 72970        }
 71
 72        public void Enable()
 73        {
 72974            if (scene == null)
 075                return;
 76
 72977            scene.OnEntityAdded -= OnEntityAdded;
 72978            scene.OnEntityRemoved -= OnEntityRemoved;
 72979            scene.OnEntityAdded += OnEntityAdded;
 72980            scene.OnEntityRemoved += OnEntityRemoved;
 72981        }
 82
 83        public void Disable()
 84        {
 72685            if (scene == null)
 086                return;
 87
 72688            scene.OnEntityAdded -= OnEntityAdded;
 72689            scene.OnEntityRemoved -= OnEntityRemoved;
 72690        }
 91
 92        SceneMetricsModel cachedModel = null;
 93
 94        public SceneMetricsModel GetLimits()
 95        {
 155096            if (cachedModel == null)
 97            {
 67398                cachedModel = new SceneMetricsModel();
 99
 673100                int parcelCount = scene.sceneData.parcels.Length;
 673101                float log = Mathf.Log(parcelCount + 1, 2);
 673102                float lineal = parcelCount;
 103
 673104                cachedModel.triangles = (int) (lineal * LimitsConfig.triangles);
 673105                cachedModel.bodies = (int) (lineal * LimitsConfig.bodies);
 673106                cachedModel.entities = (int) (lineal * LimitsConfig.entities);
 673107                cachedModel.materials = (int) (log * LimitsConfig.materials);
 673108                cachedModel.textures = (int) (log * LimitsConfig.textures);
 673109                cachedModel.meshes = (int) (log * LimitsConfig.meshes);
 673110                cachedModel.sceneHeight = (int) (log * LimitsConfig.height);
 111            }
 112
 1550113            return cachedModel;
 114        }
 115
 116        public bool IsInsideTheLimits()
 117        {
 4118            SceneMetricsModel limits = GetLimits();
 4119            SceneMetricsModel usage = GetModel();
 120
 4121            if (usage.triangles > limits.triangles)
 0122                return false;
 123
 4124            if (usage.bodies > limits.bodies)
 0125                return false;
 126
 4127            if (usage.entities > limits.entities)
 1128                return false;
 129
 3130            if (usage.materials > limits.materials)
 0131                return false;
 132
 3133            if (usage.textures > limits.textures)
 0134                return false;
 135
 3136            if (usage.meshes > limits.meshes)
 0137                return false;
 138
 3139            return true;
 140        }
 141
 142        public void SendEvent()
 143        {
 727144            if (isDirty)
 145            {
 122146                isDirty = false;
 147
 122148                Interface.WebInterface.ReportOnMetricsUpdate(scene.sceneData.id,
 149                    model.ToMetricsModel(), GetLimits().ToMetricsModel());
 150            }
 727151        }
 152
 153        protected virtual void OnEntityAdded(IDCLEntity e)
 154        {
 542155            e.OnMeshesInfoUpdated += OnEntityMeshInfoUpdated;
 542156            e.OnMeshesInfoCleaned += OnEntityMeshInfoCleaned;
 542157            model.entities++;
 542158            isDirty = true;
 542159        }
 160
 161        protected virtual void OnEntityRemoved(IDCLEntity e)
 162        {
 34163            SubstractMetrics(e);
 34164            e.OnMeshesInfoUpdated -= OnEntityMeshInfoUpdated;
 34165            e.OnMeshesInfoCleaned -= OnEntityMeshInfoCleaned;
 34166            model.entities--;
 34167            isDirty = true;
 34168        }
 169
 1076170        protected virtual void OnEntityMeshInfoUpdated(IDCLEntity entity) { AddOrReplaceMetrics(entity); }
 171
 438172        protected virtual void OnEntityMeshInfoCleaned(IDCLEntity entity) { SubstractMetrics(entity); }
 173
 174        protected void AddOrReplaceMetrics(IDCLEntity entity)
 175        {
 540176            if (entitiesMetrics.ContainsKey(entity))
 177            {
 298178                SubstractMetrics(entity);
 179            }
 180
 540181            AddMetrics(entity);
 540182        }
 183
 184        protected void SubstractMetrics(IDCLEntity entity)
 185        {
 552186            if (!entitiesMetrics.ContainsKey(entity))
 187            {
 25188                return;
 189            }
 190
 527191            EntityMetrics entityMetrics = entitiesMetrics[entity];
 192
 527193            RemoveEntitiesMaterial(entityMetrics);
 527194            RemoveEntityMeshes(entityMetrics);
 195
 527196            model.materials = uniqueMaterialsRefCount.Count;
 527197            model.meshes = uniqueMeshesRefCount.Count;
 527198            model.triangles -= entityMetrics.triangles;
 527199            model.bodies -= entityMetrics.bodies;
 200
 527201            if (entitiesMetrics.ContainsKey(entity))
 202            {
 527203                entitiesMetrics.Remove(entity);
 204            }
 205
 527206            isDirty = true;
 527207        }
 208
 209        protected void AddMetrics(IDCLEntity entity)
 210        {
 540211            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
 540217            if (entity.meshRootGameObject.GetComponent<MaterialTransitionController>()) // the object's MaterialTransiti
 218            {
 2219                return;
 220            }
 221
 538222            EntityMetrics entityMetrics = new EntityMetrics();
 223
 538224            int visualMeshRawTriangles = 0;
 225
 226            //NOTE(Brian): If this proves to be too slow we can spread it with a Coroutine spooler.
 538227            MeshFilter[] meshFilters = entity.meshesInfo.meshFilters;
 228
 2088229            for (int i = 0; i < meshFilters.Length; i++)
 230            {
 506231                MeshFilter mf = meshFilters[i];
 232
 506233                if (mf != null && mf.sharedMesh != null)
 234                {
 506235                    visualMeshRawTriangles += mf.sharedMesh.triangles.Length;
 506236                    AddMesh(entityMetrics, mf.sharedMesh);
 506237                    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
 538245            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.
 538249            entityMetrics.triangles = visualMeshRawTriangles / 3;
 538250            entityMetrics.bodies = entity.meshesInfo.meshFilters.Length;
 251
 538252            model.materials = uniqueMaterialsRefCount.Count;
 538253            model.meshes = uniqueMeshesRefCount.Count;
 538254            model.triangles += entityMetrics.triangles;
 538255            model.bodies += entityMetrics.bodies;
 256
 538257            if (!entitiesMetrics.ContainsKey(entity))
 258            {
 538259                entitiesMetrics.Add(entity, entityMetrics);
 538260            }
 261            else
 262            {
 0263                entitiesMetrics[entity] = entityMetrics;
 264            }
 265
 538266            if (VERBOSE)
 267            {
 0268                Debug.Log("SceneMetrics: entity " + entity.entityId + " metrics " + entityMetrics.ToString());
 269            }
 270
 538271            isDirty = true;
 538272        }
 273
 274        void CalculateMaterials(IDCLEntity entity, EntityMetrics entityMetrics)
 275        {
 538276            var originalMaterials = Environment.i.world.sceneBoundsChecker.GetOriginalMaterials(entity.meshesInfo);
 538277            if (originalMaterials == null)
 17278                return;
 279
 521280            int originalMaterialsCount = originalMaterials.Count;
 281
 2110282            for (int i = 0; i < originalMaterialsCount; i++)
 283            {
 534284                AddMaterial(entityMetrics, originalMaterials[i]);
 285
 534286                if (VERBOSE)
 0287                    Debug.Log($"SceneMetrics: material (style: {Environment.i.world.sceneBoundsChecker.GetFeedbackStyle(
 288            }
 521289        }
 290
 291        void AddMesh(EntityMetrics entityMetrics, Mesh mesh)
 292        {
 506293            if (!uniqueMeshesRefCount.ContainsKey(mesh))
 294            {
 388295                uniqueMeshesRefCount.Add(mesh, 1);
 388296            }
 297            else
 298            {
 118299                uniqueMeshesRefCount[mesh] += 1;
 300            }
 301
 506302            if (!entityMetrics.meshes.ContainsKey(mesh))
 303            {
 444304                entityMetrics.meshes.Add(mesh, 1);
 444305            }
 306            else
 307            {
 62308                entityMetrics.meshes[mesh] += 1;
 309            }
 62310        }
 311
 312        void RemoveEntityMeshes(EntityMetrics entityMetrics)
 313        {
 527314            var entityMeshes = entityMetrics.meshes;
 527315            using (var iterator = entityMeshes.GetEnumerator())
 316            {
 958317                while (iterator.MoveNext())
 318                {
 431319                    if (uniqueMeshesRefCount.ContainsKey(iterator.Current.Key))
 320                    {
 431321                        uniqueMeshesRefCount[iterator.Current.Key] -= iterator.Current.Value;
 431322                        if (uniqueMeshesRefCount[iterator.Current.Key] <= 0)
 323                        {
 375324                            uniqueMeshesRefCount.Remove(iterator.Current.Key);
 325                        }
 326                    }
 327                }
 527328            }
 527329        }
 330
 331        void AddMaterial(EntityMetrics entityMetrics, Material material)
 332        {
 534333            if (material == null)
 0334                return;
 335
 534336            if (!uniqueMaterialsRefCount.ContainsKey(material))
 337            {
 428338                uniqueMaterialsRefCount.Add(material, 1);
 428339            }
 340            else
 341            {
 106342                uniqueMaterialsRefCount[material] += 1;
 343            }
 344
 534345            if (!entityMetrics.materials.ContainsKey(material))
 346            {
 487347                entityMetrics.materials.Add(material, 1);
 487348            }
 349            else
 350            {
 47351                entityMetrics.materials[material] += 1;
 352            }
 47353        }
 354
 355        void RemoveEntitiesMaterial(EntityMetrics entityMetrics)
 356        {
 527357            var entityMaterials = entityMetrics.materials;
 527358            using (var iterator = entityMaterials.GetEnumerator())
 359            {
 1007360                while (iterator.MoveNext())
 361                {
 480362                    if (uniqueMaterialsRefCount.ContainsKey(iterator.Current.Key))
 363                    {
 480364                        uniqueMaterialsRefCount[iterator.Current.Key] -= iterator.Current.Value;
 480365                        if (uniqueMaterialsRefCount[iterator.Current.Key] <= 0)
 366                        {
 421367                            uniqueMaterialsRefCount.Remove(iterator.Current.Key);
 368                        }
 369                    }
 370                }
 527371            }
 527372        }
 373    }
 374}