Row atlas seems like it is working!

This commit is contained in:
Jamie Wong 2018-01-28 12:29:41 -08:00
parent 4fcd40da98
commit 31829c4aa0
6 changed files with 50 additions and 23 deletions

View File

@ -149,6 +149,10 @@ export class CanvasContext {
this.setViewportScope({ physicalBounds }, cb)
}
setViewport(physicalBounds: Rect, cb: (context: regl.Context) => void) {
this.setViewportScope({ physicalBounds }, cb)
}
getMaxTextureSize() {
return this.gl.limits.maxTextureSize
}

View File

@ -4,14 +4,16 @@ import { RectangleBatch } from './rectangle-batch-renderer'
import { CanvasContext } from './canvas-context';
import { Vec2, Rect, AffineTransform } from './math'
import { LRUCache } from './lru-cache'
import { Color } from './color'
const MAX_BATCH_SIZE = 10000
class RowAtlas<K> {
private texture: regl.Texture
texture: regl.Texture
private framebuffer: regl.Framebuffer
private renderToFramebuffer: regl.Command<{}>
private rowCache: LRUCache<K, number>
private clearLineBatch: RectangleBatch
constructor(private canvasContext: CanvasContext) {
this.texture = canvasContext.gl.texture({
@ -25,6 +27,8 @@ class RowAtlas<K> {
this.renderToFramebuffer = canvasContext.gl({
framebuffer: this.framebuffer
})
this.clearLineBatch = canvasContext.createRectangleBatch()
this.clearLineBatch.addRect(Rect.unit, new Color(1, 1, 1, 1))
}
has(key: K) { return this.rowCache.has(key) }
@ -53,20 +57,23 @@ class RowAtlas<K> {
let row = this.rowCache.get(key)
if (row != null) {
// Already cached!
return
continue
}
// Not cached -- we'll have to actually render
row = this.allocateLine(key)
const textureRect = new Rect(
new Vec2(0, row),
new Vec2(this.texture.width, 1)
)
this.canvasContext.drawRectangleBatch({
batch: this.clearLineBatch,
configSpaceSrcRect: Rect.unit,
physicalSpaceDstRect: textureRect
})
render(textureRect, key)
}
})
return
}
renderViaAtlas(key: K, dstRect: Rect): boolean {
@ -165,7 +172,7 @@ export class FlamechartRenderer {
private root: RangeTreeNode
private rowAtlas: RowAtlas<RangeTreeLeafNode>
constructor(private canvasContext: CanvasContext, flamechart: Flamechart) {
constructor(private canvasContext: CanvasContext, private flamechart: Flamechart) {
const nLayers = flamechart.getLayers().length
this.rowAtlas = new RowAtlas(canvasContext)
@ -173,7 +180,7 @@ export class FlamechartRenderer {
for (let stackDepth = 0; stackDepth < nLayers; stackDepth++) {
const leafNodes: RangeTreeLeafNode[] = []
const y = stackDepth + 1
const y = stackDepth
let minLeft = Infinity
let maxRight = -Infinity
@ -229,9 +236,7 @@ export class FlamechartRenderer {
// which is even more expensive than not using a cache at all! Instead,
// we'll cache the first 2 entries in that case, and re-use that cache each time,
// while rendering the final 2 items without use of the cache.
// An exception here is if the node is already in the cache!
let useCache = renderedBatchCount++ < cacheCapacity || this.rowAtlas.has(leaf)
let useCache = renderedBatchCount++ < cacheCapacity
if (useCache) {
cachedLeaves.push(leaf)
} else {
@ -240,17 +245,24 @@ export class FlamechartRenderer {
})
this.rowAtlas.writeToAtlasIfNeeded(cachedLeaves, (textureDstRect, leaf) => {
const configSpaceBounds = new Rect(
new Vec2(0, leaf.getBounds().top()),
new Vec2(this.flamechart.getTotalWeight(), 1)
)
this.canvasContext.drawRectangleBatch({
batch: leaf.getBatch(),
configSpaceSrcRect: leaf.getBounds(),
configSpaceSrcRect: configSpaceBounds,
physicalSpaceDstRect: textureDstRect
})
})
const configToPhysical = AffineTransform.betweenRects(configSpaceSrcRect, physicalSpaceDstRect)
for (let leaf of cachedLeaves) {
const configSpaceLeafBounds = leaf.getBounds()
const physicalLeafBounds = configToPhysical.transformRect(configSpaceLeafBounds)
const configSpaceBounds = new Rect(
new Vec2(0, leaf.getBounds().top()),
new Vec2(this.flamechart.getTotalWeight(), 1)
)
const physicalLeafBounds = configToPhysical.transformRect(configSpaceBounds)
if (!this.rowAtlas.renderViaAtlas(leaf, physicalLeafBounds)) {
console.error('Failed to render from cache')
}
@ -263,5 +275,14 @@ export class FlamechartRenderer {
physicalSpaceDstRect
})
}
// Overlay the atlas on top of the canvas for debugging
/*
this.canvasContext.drawTexture({
texture: this.rowAtlas.texture,
srcRect: new Rect(Vec2.zero, new Vec2(this.rowAtlas.texture.width, this.rowAtlas.texture.height)),
dstRect: new Rect(Vec2.zero, new Vec2(800, 800))
})
*/
}
}

View File

@ -195,7 +195,7 @@ export class FlamechartPanZoomView extends ReloadableComponent<FlamechartPanZoom
const renderFrameLabelAndChildren = (frame: FlamechartFrame, depth = 0) => {
const width = frame.end - frame.start
const configSpaceBounds = new Rect(
new Vec2(frame.start, depth + 1),
new Vec2(frame.start, depth),
new Vec2(width, 1)
)
@ -281,7 +281,7 @@ export class FlamechartPanZoomView extends ReloadableComponent<FlamechartPanZoom
if (this.lastBounds == null) {
this.setConfigSpaceViewportRect(new Rect(
new Vec2(0, 0),
new Vec2(0, -1),
new Vec2(this.configSpaceSize().x, height / this.LOGICAL_VIEW_SPACE_FRAME_HEIGHT)
))
} else if (windowResized) {
@ -308,7 +308,7 @@ export class FlamechartPanZoomView extends ReloadableComponent<FlamechartPanZoom
if (this.props.configSpaceViewportRect.isEmpty()) return
this.props.canvasContext.renderInto(this.container, () => {
this.props.canvasContext.renderInto(this.container, (context) => {
this.props.flamechartRenderer.render({
physicalSpaceDstRect: new Rect(Vec2.zero, this.physicalViewSize()),
configSpaceSrcRect: this.props.configSpaceViewportRect
@ -430,7 +430,7 @@ export class FlamechartPanZoomView extends ReloadableComponent<FlamechartPanZoom
const setHoveredLabel = (frame: FlamechartFrame, depth = 0) => {
const width = frame.end - frame.start
const configSpaceBounds = new Rect(
new Vec2(frame.start, depth + 1),
new Vec2(frame.start, depth),
new Vec2(width, 1)
)
if (configSpaceMouse.x < configSpaceBounds.left()) return null
@ -585,11 +585,13 @@ export class FlamechartView extends ReloadableComponent<FlamechartViewProps, Fla
)
}
private minConfigSpaceViewportRectWidth() { return 3 * this.props.flamechart.getMinFrameWidth(); }
private minConfigSpaceViewportRectWidth() {
return Math.min(this.props.flamechart.getTotalWeight(), 3 * this.props.flamechart.getMinFrameWidth());
}
private setConfigSpaceViewportRect = (viewportRect: Rect): void => {
const configSpaceOriginBounds = new Rect(
new Vec2(0, 0),
new Vec2(0, -1),
Vec2.max(new Vec2(0, 0), this.configSpaceSize().minus(viewportRect.size))
)

View File

@ -83,9 +83,9 @@ export class List<V> {
node.prev.next = node.next
node.next = null
node.prev = null
}
this.size--
}
}
}
interface LRUCacheNode<K, V> {

View File

@ -157,9 +157,8 @@ export class RectangleBatchRenderer {
const viewportSize = new Vec2(context.viewportWidth, context.viewportHeight)
const physicalToNDC = AffineTransform
.withTranslation(new Vec2(-1, 1))
.withScale(new Vec2(2, -2).dividedByPointwise(viewportSize))
const physicalToNDC = AffineTransform.withTranslation(new Vec2(-1, 1))
.times(AffineTransform.withScale(new Vec2(2, -2).dividedByPointwise(viewportSize)))
return physicalToNDC.times(configToPhysical).flatten()
}

1
sample/tall.txt Normal file
View File

@ -0,0 +1 @@
a;b;c;d;e;f;g;h;i;j;k;l;m;n;o;p;q;r;s;t;u;v;w;x;y;z 1