Browse Source

Canvas2D: perf improvement, new metric

 - optimized BoundingInfo recompute
 - adding the boundingInfoRecomputeCounter metric property
nockawa 9 years ago
parent
commit
7fc410f792

+ 10 - 1
src/Canvas2d/babylon.canvas2d.ts

@@ -80,6 +80,7 @@
             this._updatePositioningCounter     = new PerfCounter();
             this._updateLocalTransformCounter  = new PerfCounter();
             this._updateGlobalTransformCounter = new PerfCounter();
+            this._boundingInfoRecomputeCounter = new PerfCounter();
 
             this._profileInfoText = null;
 
@@ -214,6 +215,10 @@
             return this._updateGlobalTransformCounter;
         }
 
+        public get boundingInfoRecomputeCounter(): PerfCounter {
+            return this._boundingInfoRecomputeCounter;
+        }
+
         protected _canvasPreInit(settings: any) {
             let cachingStrategy = (settings.cachingStrategy == null) ? Canvas2D.CACHESTRATEGY_DONTCACHE : settings.cachingStrategy;
             this._cachingStrategy = cachingStrategy;
@@ -961,6 +966,7 @@
             this._updatePositioningCounter.fetchNewFrame();
             this._updateLocalTransformCounter.fetchNewFrame();
             this._updateGlobalTransformCounter.fetchNewFrame();
+            this._boundingInfoRecomputeCounter.fetchNewFrame();
         }
 
         private _fetchPerfMetrics() {
@@ -975,6 +981,7 @@
             this._updatePositioningCounter.addCount(0, true);
             this._updateLocalTransformCounter.addCount(0, true);
             this._updateGlobalTransformCounter.addCount(0, true);
+            this._boundingInfoRecomputeCounter.addCount(0, true);
         }
 
         private _updateProfileCanvas() {
@@ -995,7 +1002,8 @@
                     ` - Update Layout: ${this.updateLayoutCounter.current}, (avg:${format(this.updateLayoutCounter.lastSecAverage)}, t:${format(this.updateLayoutCounter.total)})\n` + 
                     ` - Update Positioning: ${this.updatePositioningCounter.current}, (avg:${format(this.updatePositioningCounter.lastSecAverage)}, t:${format(this.updatePositioningCounter.total)})\n` + 
                     ` - Update Local  Trans: ${this.updateLocalTransformCounter.current}, (avg:${format(this.updateLocalTransformCounter.lastSecAverage)}, t:${format(this.updateLocalTransformCounter.total)})\n` + 
-                    ` - Update Global Trans: ${this.updateGlobalTransformCounter.current}, (avg:${format(this.updateGlobalTransformCounter.lastSecAverage)}, t:${format(this.updateGlobalTransformCounter.total)})\n`;
+                    ` - Update Global Trans: ${this.updateGlobalTransformCounter.current}, (avg:${format(this.updateGlobalTransformCounter.lastSecAverage)}, t:${format(this.updateGlobalTransformCounter.total)})\n` + 
+                    ` - BoundingInfo Recompute: ${this.boundingInfoRecomputeCounter.current}, (avg:${format(this.boundingInfoRecomputeCounter.lastSecAverage)}, t:${format(this.boundingInfoRecomputeCounter.total)})\n`;
             this._profileInfoText.text = p;
         }
 
@@ -1091,6 +1099,7 @@
         private _updatePositioningCounter    : PerfCounter;
         private _updateGlobalTransformCounter: PerfCounter;
         private _updateLocalTransformCounter : PerfCounter;
+        private _boundingInfoRecomputeCounter: PerfCounter;
 
         private _profileInfoText: Text2D;
 

+ 18 - 9
src/Canvas2d/babylon.prim2dBase.ts

@@ -1341,7 +1341,7 @@
             this._layoutEngine = CanvasLayoutEngine.Singleton;
             this._size = null; //Size.Zero();
             this._actualSize = null;
-            this._boundingSize = null;
+            this._boundingSize = Size.Zero();
             this._layoutArea = Size.Zero();
             this._layoutAreaPos = Vector2.Zero();
             this._marginOffset = Vector2.Zero();
@@ -1589,7 +1589,7 @@
          */
         public static marginAlignmentProperty: Prim2DPropInfo;
 
-        @instanceLevelProperty(1, pi => Prim2DBase.actualPositionProperty = pi, false, true)
+        @instanceLevelProperty(1, pi => Prim2DBase.actualPositionProperty = pi, false, false, true)
         /**
          * Return the position where the primitive is rendered in the Canvas, this position may be different than the one returned by the position property due to layout/alignment/margin/padding computing
          */
@@ -1633,7 +1633,7 @@
          * Use this property to set a new Vector2 object, otherwise to change only the x/y use Prim2DBase.x or y properties.
          * Setting this property may have no effect is specific alignment are in effect.
          */
-        @dynamicLevelProperty(1, pi => Prim2DBase.positionProperty = pi, false, true)
+        @dynamicLevelProperty(1, pi => Prim2DBase.positionProperty = pi, false, false, true)
         public get position(): Vector2 {
             return this._position || Prim2DBase._nullPosition;
         }
@@ -1716,7 +1716,7 @@
                     return Prim2DBase.nullSize;
                 }
 
-                if (this._boundingSize) {
+                if (!this._isFlagSet(SmartPropertyPrim.flagBoundingInfoDirty)) {
                     return this._boundingSize;
                 }
 
@@ -2099,13 +2099,17 @@
             return this._localTransform;
         }
 
+        private static _bMax = Vector2.Zero();
+
         /**
          * Get the boundingInfo associated to the primitive and its children.
          * The value is supposed to be always up to date
          */
         public get boundingInfo(): BoundingInfo2D {
             if (this._isFlagSet(SmartPropertyPrim.flagBoundingInfoDirty)) {
-
+                if (this.owner) {
+                    this.owner.boundingInfoRecomputeCounter.addCount(1, false);
+                }
                 if (this.isSizedByContent) {
                     this._boundingInfo.clear();
                 } else {
@@ -2119,9 +2123,10 @@
                     bi.unionToRef(tps, bi);
                 }
 
-                this._boundingSize = Size.Zero();
-                let m = this._boundingInfo.max();
-                this._boundingSize = new Size((!this._size || this._size.width == null) ? Math.ceil(m.x) : this._size.width, (!this._size || this._size.height == null) ? Math.ceil(m.y) : this._size.height);
+                this._boundingInfo.maxToRef(Prim2DBase._bMax);
+                this._boundingSize.copyFromFloats(
+                    (!this._size || this._size.width == null) ? Math.ceil(Prim2DBase._bMax.x) : this._size.width,
+                    (!this._size || this._size.height == null) ? Math.ceil(Prim2DBase._bMax.y) : this._size.height);
 
                 this._clearFlags(SmartPropertyPrim.flagBoundingInfoDirty);
             }
@@ -2515,7 +2520,11 @@
             let positioningComputed = positioningDirty && !this._isFlagSet(SmartPropertyPrim.flagPositioningDirty);
             let autoContentChanged = false;
             if (this.isSizeAuto) {
-                autoContentChanged = (!this._lastAutoSizeArea.equals(this.size));
+                if (!this._lastAutoSizeArea) {
+                    autoContentChanged = this.size!==null;
+                } else {
+                    autoContentChanged = (!this._lastAutoSizeArea.equals(this.size));
+                }
             }
 
             // Check for positioning update

+ 16 - 10
src/Canvas2d/babylon.smartPropertyPrim.ts

@@ -13,6 +13,7 @@
         kind: number;
         name: string;
         dirtyBoundingInfo: boolean;
+        dirtyParentBoundingInfo: boolean;
         typeLevelCompare: boolean;
     }
 
@@ -270,7 +271,7 @@
             return this._propInfo;
         }
 
-        private static _createPropInfo(target: Object, propName: string, propId: number, dirtyBoundingInfo: boolean, typeLevelCompare: boolean, kind: number): Prim2DPropInfo {
+        private static _createPropInfo(target: Object, propName: string, propId: number, dirtyBoundingInfo: boolean, dirtyParentBoundingBox: boolean, typeLevelCompare: boolean, kind: number): Prim2DPropInfo {
             let dic = ClassTreeInfo.getOrRegister<Prim2DClassInfo, Prim2DPropInfo>(target, () => new Prim2DClassInfo());
             var node = dic.getLevelOf(target);
 
@@ -286,6 +287,7 @@
             propInfo.kind = kind;
             propInfo.name = propName;
             propInfo.dirtyBoundingInfo = dirtyBoundingInfo;
+            propInfo.dirtyParentBoundingInfo = dirtyParentBoundingBox;
             propInfo.typeLevelCompare = typeLevelCompare;
             node.levelContent.add(propName, propInfo);
 
@@ -342,7 +344,6 @@
             if (this instanceof Prim2DBase) {
                 let curprim: Prim2DBase = (<any>this);
                 while (curprim) {
-                    curprim._boundingSize = null;
                     curprim._setFlags(SmartPropertyPrim.flagBoundingInfoDirty);
                     if (curprim.isSizeAuto) {
                         curprim.onPrimitivePropertyDirty(Prim2DBase.sizeProperty.flagId);
@@ -364,6 +365,11 @@
             // If the property change also dirty the boundingInfo, update the boundingInfo dirty flags
             if (propInfo.dirtyBoundingInfo) {
                 this._boundingBoxDirty();
+            } else if (propInfo.dirtyParentBoundingInfo) {
+                let p: SmartPropertyPrim = (<any>this)._parent;
+                if (p != null) {
+                    p._boundingBoxDirty();
+                }
             }
 
             // Trigger property changed
@@ -463,10 +469,10 @@
 
         }
 
-        static _hookProperty<T>(propId: number, piStore: (pi: Prim2DPropInfo) => void, typeLevelCompare: boolean, dirtyBoundingInfo: boolean, kind: number): (target: Object, propName: string | symbol, descriptor: TypedPropertyDescriptor<T>) => void {
+        static _hookProperty<T>(propId: number, piStore: (pi: Prim2DPropInfo) => void, typeLevelCompare: boolean, dirtyBoundingInfo: boolean, dirtyParentBoundingBox: boolean, kind: number): (target: Object, propName: string | symbol, descriptor: TypedPropertyDescriptor<T>) => void {
             return (target: Object, propName: string | symbol, descriptor: TypedPropertyDescriptor<T>) => {
 
-                var propInfo = SmartPropertyPrim._createPropInfo(target, <string>propName, propId, dirtyBoundingInfo, typeLevelCompare, kind);
+                var propInfo = SmartPropertyPrim._createPropInfo(target, <string>propName, propId, dirtyBoundingInfo, dirtyParentBoundingBox, typeLevelCompare, kind);
                 if (piStore) {
                     piStore(propInfo);
                 }
@@ -630,15 +636,15 @@
         protected _instanceDirtyFlags: number;
     }
 
-    export function modelLevelProperty<T>(propId: number, piStore: (pi: Prim2DPropInfo) => void, typeLevelCompare = false, dirtyBoundingInfo = false): (target: Object, propName: string | symbol, descriptor: TypedPropertyDescriptor<T>) => void {
-        return SmartPropertyPrim._hookProperty(propId, piStore, typeLevelCompare, dirtyBoundingInfo, Prim2DPropInfo.PROPKIND_MODEL);
+    export function modelLevelProperty<T>(propId: number, piStore: (pi: Prim2DPropInfo) => void, typeLevelCompare = false, dirtyBoundingInfo = false, dirtyParentBoundingBox = false): (target: Object, propName: string | symbol, descriptor: TypedPropertyDescriptor<T>) => void {
+        return SmartPropertyPrim._hookProperty(propId, piStore, typeLevelCompare, dirtyBoundingInfo, dirtyParentBoundingBox, Prim2DPropInfo.PROPKIND_MODEL);
     }
 
-    export function instanceLevelProperty<T>(propId: number, piStore: (pi: Prim2DPropInfo) => void, typeLevelCompare = false, dirtyBoundingInfo = false): (target: Object, propName: string | symbol, descriptor: TypedPropertyDescriptor<T>) => void {
-        return SmartPropertyPrim._hookProperty(propId, piStore, typeLevelCompare, dirtyBoundingInfo, Prim2DPropInfo.PROPKIND_INSTANCE);
+    export function instanceLevelProperty<T>(propId: number, piStore: (pi: Prim2DPropInfo) => void, typeLevelCompare = false, dirtyBoundingInfo = false, dirtyParentBoundingBox = false): (target: Object, propName: string | symbol, descriptor: TypedPropertyDescriptor<T>) => void {
+        return SmartPropertyPrim._hookProperty(propId, piStore, typeLevelCompare, dirtyBoundingInfo, dirtyParentBoundingBox, Prim2DPropInfo.PROPKIND_INSTANCE);
     }
 
-    export function dynamicLevelProperty<T>(propId: number, piStore: (pi: Prim2DPropInfo) => void, typeLevelCompare = false, dirtyBoundingInfo = false): (target: Object, propName: string | symbol, descriptor: TypedPropertyDescriptor<T>) => void {
-        return SmartPropertyPrim._hookProperty(propId, piStore, typeLevelCompare, dirtyBoundingInfo, Prim2DPropInfo.PROPKIND_DYNAMIC);
+    export function dynamicLevelProperty<T>(propId: number, piStore: (pi: Prim2DPropInfo) => void, typeLevelCompare = false, dirtyBoundingInfo = false, dirtyParentBoundingBox = false): (target: Object, propName: string | symbol, descriptor: TypedPropertyDescriptor<T>) => void {
+        return SmartPropertyPrim._hookProperty(propId, piStore, typeLevelCompare, dirtyBoundingInfo, dirtyParentBoundingBox, Prim2DPropInfo.PROPKIND_DYNAMIC);
     }
 }