diff --git a/application.tsx b/application.tsx index a5ccf7b..fbc0e37 100644 --- a/application.tsx +++ b/application.tsx @@ -176,32 +176,6 @@ export class GLCanvas extends ReloadableComponent { } } -function rectangleBatchForFlamechart(canvasContext: CanvasContext, flamechart: Flamechart) { - console.time('rectangle batch generation') - - const batch = canvasContext.createRectangleBatch() - - const layers = flamechart.getLayers() - for (let i = 0; i < layers.length; i++) { - const layer = layers[i] - for (let flamechartFrame of layer) { - const configSpaceBounds = new Rect( - new Vec2(flamechartFrame.start, i + 1), - new Vec2(flamechartFrame.end - flamechartFrame.start, 1) - ) - const color = flamechart.getColorForFrame(flamechartFrame.node.frame) - batch.addRect(configSpaceBounds, color) - } - } - - // GPU upload - batch.uploadToGPU() - - console.timeEnd('rectangle batch generation') - - return batch -} - export class Application extends ReloadableComponent<{}, ApplicationState> { constructor() { super() diff --git a/canvas-context.ts b/canvas-context.ts index fc1c700..54b8d92 100644 --- a/canvas-context.ts +++ b/canvas-context.ts @@ -1,7 +1,7 @@ import * as regl from 'regl' import { RectangleBatchRenderer, RectangleBatch, RectangleBatchRendererProps } from './rectangle-batch-renderer'; import { ViewportRectangleRenderer, ViewportRectangleRendererProps } from './overlay-rectangle-renderer'; -import { TextureCachedRenderer, TextureRenderer } from './texture-catched-renderer' +import { TextureCachedRenderer, TextureRenderer, TextureRendererProps } from './texture-catched-renderer' import { Vec2, Rect } from './math'; @@ -12,7 +12,7 @@ interface SetViewportScopeProps { } export class CanvasContext { - private gl: regl.Instance + public gl: regl.Instance private rectangleBatchRenderer: RectangleBatchRenderer private viewportRectangleRenderer: ViewportRectangleRenderer private textureRenderer: TextureRenderer @@ -120,6 +120,12 @@ export class CanvasContext { this.rectangleBatchRenderer.render(props) } + drawTexture(props: TextureRendererProps) { + this.gl({})((context: regl.Context) => { + this.textureRenderer.render(context, props) + }) + } + createRectangleBatch(): RectangleBatch { return new RectangleBatch(this.gl) } @@ -146,4 +152,8 @@ export class CanvasContext { ) this.setViewportScope({ physicalBounds }, cb) } + + getMaxTextureSize() { + return this.gl.limits.maxTextureSize + } } \ No newline at end of file diff --git a/flamechart-renderer.ts b/flamechart-renderer.ts index ad8cd05..78fc367 100644 --- a/flamechart-renderer.ts +++ b/flamechart-renderer.ts @@ -1,3 +1,4 @@ +import * as regl from 'regl' import { Flamechart } from './flamechart' import { RectangleBatch } from './rectangle-batch-renderer' import { CanvasContext } from './canvas-context'; @@ -129,16 +130,65 @@ class BoundedLayer { export class FlamechartRenderer { private layers: BoundedLayer[] = [] + private texture: regl.Texture | null = null - constructor(canvasContext: CanvasContext, flamechart: Flamechart) { - for (let i = 0; i < flamechart.getLayers().length; i++) { + constructor(private canvasContext: CanvasContext, flamechart: Flamechart) { + const nLayers = flamechart.getLayers().length + const maxTextureSize = canvasContext.getMaxTextureSize() + + if (nLayers > maxTextureSize) { + throw new Error(`This profile has more than ${maxTextureSize} layers!`) + } + + this.texture = canvasContext.gl.texture({ + width: canvasContext.getMaxTextureSize(), + height: nLayers, + }) + const fbo = canvasContext.gl.framebuffer({ color: [this.texture] }) + + for (let i = 0; i < nLayers; i++) { this.layers.push(new BoundedLayer(canvasContext, flamechart, i)) } + + const configSpaceToNDC = AffineTransform.withScale(new Vec2(1, -1)).times( + AffineTransform.betweenRects( + new Rect(new Vec2(0, 0), new Vec2(flamechart.getTotalWeight(), nLayers)), + new Rect(new Vec2(-1, -1), new Vec2(2, 2)) + ) + ) + + canvasContext.gl({ + viewport: (context, props) => { + return { + x: 0, + y: 0, + width: canvasContext.getMaxTextureSize(), + height: nLayers + } + }, + framebuffer: fbo + })((context: regl.Context) => { + const physicalSize = new Vec2(context.drawingBufferWidth, context.drawingBufferHeight) + for (let layer of this.layers) { + layer.render({ physicalSize, configSpaceToNDC }) + } + }) + + fbo.destroy() } render(props: FlamechartRendererProps) { + if (!this.texture) return + this.canvasContext.drawTexture({ + texture: this.texture, + ndcRect: new Rect(new Vec2(-1, -1), new Vec2(2, 2)), + uvRect: new Rect(new Vec2(0, 0), new Vec2(1, 1)) + }) + + /* for (let layer of this.layers) { layer.render(props) } + */ } } \ No newline at end of file diff --git a/texture-catched-renderer.ts b/texture-catched-renderer.ts index 3c48078..a5ffa0d 100644 --- a/texture-catched-renderer.ts +++ b/texture-catched-renderer.ts @@ -1,7 +1,10 @@ import * as regl from 'regl' +import { Vec2, Rect } from './math' export class TextureRendererProps { texture: regl.Texture + ndcRect: Rect + uvRect: Rect } export class TextureRenderer { @@ -28,6 +31,11 @@ export class TextureRenderer { gl_FragColor = texture2D(texture, vUv); } `, + + depth: { + enable: false + }, + attributes: { // Cover full canvas with a rectangle // with 2 triangles using a triangle @@ -37,18 +45,26 @@ export class TextureRenderer { // | /| // |/ | // 2 +--+ 3 - position: [ - [-1, 1], - [1, 1], - [-1, -1], - [1, -1] - ], - uv: [ - [0, 1], - [1, 1], - [0, 0], - [1, 0] - ] + position: (context, props) => { + const rect = props.ndcRect + + return [ + rect.topLeft().flatten(), + rect.topRight().flatten(), + rect.bottomLeft().flatten(), + rect.bottomRight().flatten() + ] + }, + uv: (context, props) => { + const rect = props.uvRect + + return [ + rect.topLeft().flatten(), + rect.topRight().flatten(), + rect.bottomLeft().flatten(), + rect.bottomRight().flatten() + ] + } }, uniforms: { @@ -132,7 +148,11 @@ export class TextureCachedRenderer { } // Render from texture - this.textureRenderer.render(context, {texture: this.texture}) + this.textureRenderer.render(context, { + texture: this.texture, + ndcRect: new Rect(new Vec2(-1, -1), new Vec2(2, 2)), + uvRect: new Rect(new Vec2(0, 0), new Vec2(1, 1)) + }) this.lastRenderProps = props this.dirty = false }