Skip to content
Draft
34 changes: 32 additions & 2 deletions lib/CacheRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ export class CacheRenderer extends RendererBase implements IMaterial, IRenderabl

public useColorTransform: boolean = true;

/** When false, blit uses existing RTT without re-traversing children. */
private _contentDirty: boolean = true;

public alphaBlending: boolean = true;

public alphaThreshold: number = 0;
Expand All @@ -64,6 +67,19 @@ export class CacheRenderer extends RendererBase implements IMaterial, IRenderabl
return CacheRenderer.assetType;
}

public get contentDirty(): boolean {
return this._contentDirty;
}

/**
* Mark cached bitmap contents dirty (child/material/filter change).
* Does not itself traverse; next blit pass will rebuild the RTT.
*/
public markContentDirty(): void {
this._contentDirty = true;
this.invalidate();
}

/**
* The 2d texture to use as a bitmap cache.
*/
Expand Down Expand Up @@ -132,6 +148,7 @@ export class CacheRenderer extends RendererBase implements IMaterial, IRenderabl
mipmapSelector: number = 0,
maskConfig: number = 0
): void {
RendererBase._perfStats.cacheRenders++;
const container = this.node.container;

const stage = this.stage;
Expand Down Expand Up @@ -207,6 +224,8 @@ export class CacheRenderer extends RendererBase implements IMaterial, IRenderabl
// pop render target after any filters,
// required for deep filters (when node with filter has filtered child)
this.stage.popRenderTarget();

this._contentDirty = false;
}

public _updateBounds(): void {
Expand Down Expand Up @@ -278,6 +297,10 @@ export class CacheRenderer extends RendererBase implements IMaterial, IRenderabl
public onInvalidate(): void {
super.onInvalidate();

// Content + blit dirty. Hold-frame timeline no-op (scene Timeline E8) stops
// spurious SCENE_TRANSFORM bubbles that previously rebuilt RTTs every frame.
this._contentDirty = true;

for (const key in this._renderObjects)
this._renderObjects[key]._onInvalidateElements();

Expand All @@ -290,12 +313,19 @@ export class CacheRenderer extends RendererBase implements IMaterial, IRenderabl

public onInvalidateSceneTransform(): void {
(<ContainerNode> this._asset).invalidateHierarchicalProperty(HierarchicalProperty.SCENE_TRANSFORM);
this.onInvalidate();
// Parent/scene transform only moves the blit quad. Local-node content is
// transformDisabled, so rebuilding the RTT here wastes draws every frame
// a filtered/cached clip moves. Child content still invalidates via materials.
this._boundsDirty = true;
for (const key in this._renderObjects) {
this._renderObjects[key]._onInvalidateElements();
this._renderObjects[key]._onInvalidateStyle();
}
}

public onInvalidateColorTransform(): void {
(<ContainerNode> this._asset).invalidateHierarchicalProperty(HierarchicalProperty.COLOR_TRANSFORM);
this.invalidate();
this.markContentDirty();
}

public onClear(): void {
Expand Down
45 changes: 44 additions & 1 deletion lib/DefaultRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { RenderGroup } from './RenderGroup';
import { DepthRenderer } from './DepthRenderer';
import { DistanceRenderer } from './DistanceRenderer';
import { RendererBase } from './RendererBase';
import { DrawCallBatcher } from './utils/DrawCallBatcher';
import { Settings } from './Settings';
import { _IRender_MaterialClass } from './base/_IRender_MaterialClass';
import { CacheRenderer } from './CacheRenderer';

Expand Down Expand Up @@ -94,10 +96,51 @@ export class DefaultRenderer extends RendererBase {
this._renderDepthPrepass();

//this._view.target = null;
const _rt0 = (typeof performance !== 'undefined') ? performance.now() : 0;
super.render(enableDepthAndStencil, surfaceSelector, mipmapSelector, maskConfig);
const _rt1 = (typeof performance !== 'undefined') ? performance.now() : 0;

if (!maskConfig)
if (!maskConfig) {
this.view.present();
let _finishMs = 0;
const gProbe: any = <any> (typeof self !== 'undefined' ? self : globalThis);
if (gProbe.__AWAY_PERF_FINISH__) {
const _ft0 = performance.now();
try { (<any> this.stage).context._gl.finish(); } catch (e) { /* ignore */ }
_finishMs = performance.now() - _ft0;
}
const _rt2 = (typeof performance !== 'undefined') ? performance.now() : 0;
// Expose renderer composition counters for the perf harness.
const g: any = <any> (typeof self !== 'undefined' ? self : globalThis);
g.__AWAY_RENDER_SETTINGS__ = Settings;
const s = RendererBase._perfStats;
const prev = g.__AWAY_PERF__ || {};
g.__AWAY_PERF__ = { opaque: s.opaque, blended: s.blended, materialRuns: s.materialRuns,
maskSwitches: s.maskSwitches, cacheRenders: s.cacheRenders, draws: s.draws,
batchDraws: DrawCallBatcher.batchDraws, batchMerged: DrawCallBatcher.mergedDrawables,
batchCacheHits: DrawCallBatcher.cacheHits, batchCacheMisses: DrawCallBatcher.cacheMisses,
batchStaticSkips: DrawCallBatcher.staticSkips, batchStaticMissReason: DrawCallBatcher.staticMissReason, batchStaticPrefixEnd: DrawCallBatcher.staticPrefixEnd,
batchVerts: DrawCallBatcher.vertsSubmitted, batchIdx: DrawCallBatcher.idxSubmitted,
batchUploadBytes: DrawCallBatcher.uploadBytes, batchMaxVerts: DrawCallBatcher.maxBatchVerts,
msTraverse: +s.msTraverse.toFixed(3), msDraw: +s.msDraw.toFixed(3),
msPresent: +(_rt2 - _rt1).toFixed(3),
msGpuFinish: +_finishMs.toFixed(3),
msRender: +(_rt2 - _rt0).toFixed(3),
msAvm: prev.msAvm, msMouse: prev.msMouse, msFrame: prev.msFrame };
s.opaque = s.blended = s.materialRuns = s.maskSwitches = s.cacheRenders = s.draws = 0;
s.batchDraws = s.batchMerged = 0;
s.msTraverse = s.msDraw = 0;
DrawCallBatcher.batchDraws = 0;
DrawCallBatcher.mergedDrawables = 0;
DrawCallBatcher.skippedSingles = 0;
DrawCallBatcher.cacheHits = 0;
DrawCallBatcher.cacheMisses = 0;
DrawCallBatcher.staticSkips = 0;
DrawCallBatcher.vertsSubmitted = 0;
DrawCallBatcher.idxSubmitted = 0;
DrawCallBatcher.uploadBytes = 0;
DrawCallBatcher.maxBatchVerts = 0;
}
}

public onClear(): void {
Expand Down
Loading