mirror of
https://github.com/jlfwong/speedscope.git
synced 2024-11-22 12:53:23 +03:00
I think it works!!!!!
This commit is contained in:
parent
838cc06ff5
commit
53656fef43
@ -12,7 +12,6 @@ import {Profile, Frame} from './profile'
|
||||
import {Flamechart} from './flamechart'
|
||||
import { FlamechartView } from './flamechart-view'
|
||||
import { FontFamily, FontSize, Colors } from './style'
|
||||
import { FrameColorGenerator } from './color'
|
||||
|
||||
const enum SortOrder {
|
||||
CHRONO,
|
||||
@ -224,13 +223,26 @@ export class Application extends ReloadableComponent<{}, ApplicationState> {
|
||||
|
||||
const frames: Frame[] = []
|
||||
profile.forEachFrame(f => frames.push(f))
|
||||
const colorGenerator = new FrameColorGenerator(frames)
|
||||
function key(f: Frame) {
|
||||
return (f.file || '') + f.name
|
||||
}
|
||||
function compare(a: Frame, b: Frame) {
|
||||
return key(a) > key(b) ? 1 : -1
|
||||
}
|
||||
frames.sort(compare)
|
||||
const frameToColorBucket = new Map<Frame, number>()
|
||||
for (let i = 0; i < frames.length; i++) {
|
||||
frameToColorBucket.set(frames[i], Math.floor(255 * i / frames.length))
|
||||
}
|
||||
function getColorBucketForFrame(frame: Frame) {
|
||||
return frameToColorBucket.get(frame) || 0
|
||||
}
|
||||
|
||||
const flamechart = new Flamechart({
|
||||
getTotalWeight: profile.getTotalWeight.bind(profile),
|
||||
forEachCall: profile.forEachCall.bind(profile),
|
||||
formatValue: profile.formatValue.bind(profile),
|
||||
getColorForFrame: colorGenerator.getColorForFrame.bind(colorGenerator)
|
||||
getColorBucketForFrame
|
||||
})
|
||||
const flamechartRenderer = new FlamechartRenderer(this.canvasContext, flamechart)
|
||||
|
||||
@ -238,7 +250,7 @@ export class Application extends ReloadableComponent<{}, ApplicationState> {
|
||||
getTotalWeight: profile.getTotalNonIdleWeight.bind(profile),
|
||||
forEachCall: profile.forEachCallGrouped.bind(profile),
|
||||
formatValue: profile.formatValue.bind(profile),
|
||||
getColorForFrame: colorGenerator.getColorForFrame.bind(colorGenerator)
|
||||
getColorBucketForFrame
|
||||
})
|
||||
const sortedFlamechartRenderer = new FlamechartRenderer(this.canvasContext, sortedFlamechart)
|
||||
|
||||
|
@ -5,7 +5,7 @@ import { TextureCachedRenderer, TextureRenderer, TextureRendererProps } from './
|
||||
import { StatsPanel } from './stats'
|
||||
|
||||
import { Vec2, Rect } from './math';
|
||||
import { OutlineRenderer, OutlineRendererProps } from './outline-renderer';
|
||||
import { FlamechartColorPassRenderer, FlamechartColorPassRenderProps } from './flamechart-color-pass-renderer';
|
||||
|
||||
type FrameCallback = () => void
|
||||
|
||||
@ -18,7 +18,7 @@ export class CanvasContext {
|
||||
private rectangleBatchRenderer: RectangleBatchRenderer
|
||||
private viewportRectangleRenderer: ViewportRectangleRenderer
|
||||
private textureRenderer: TextureRenderer
|
||||
private outlineRenderer: OutlineRenderer
|
||||
private flamechartColorPassRenderer: FlamechartColorPassRenderer
|
||||
private setViewportScope: regl.Command<{ physicalBounds: Rect }>
|
||||
private setScissor: regl.Command<{}>
|
||||
|
||||
@ -36,7 +36,7 @@ export class CanvasContext {
|
||||
this.rectangleBatchRenderer = new RectangleBatchRenderer(this.gl)
|
||||
this.viewportRectangleRenderer = new ViewportRectangleRenderer(this.gl)
|
||||
this.textureRenderer = new TextureRenderer(this.gl)
|
||||
this.outlineRenderer = new OutlineRenderer(this.gl)
|
||||
this.flamechartColorPassRenderer = new FlamechartColorPassRenderer(this.gl)
|
||||
this.setScissor = this.gl({ scissor: { enable: true } })
|
||||
this.setViewportScope = this.gl<SetViewportScopeProps>({
|
||||
context: {
|
||||
@ -125,8 +125,8 @@ export class CanvasContext {
|
||||
this.textureRenderer.render(props)
|
||||
}
|
||||
|
||||
drawOutlines(props: OutlineRendererProps) {
|
||||
this.outlineRenderer.render(props)
|
||||
drawFlamechartColorPass(props: FlamechartColorPassRenderProps) {
|
||||
this.flamechartColorPassRenderer.render(props)
|
||||
}
|
||||
|
||||
createRectangleBatch(): RectangleBatch {
|
||||
|
1
color.ts
1
color.ts
@ -27,6 +27,7 @@ function fract(x: number) {
|
||||
return x - Math.floor(x)
|
||||
}
|
||||
|
||||
// TODO(jlfwong): Can probably delete this?
|
||||
export class FrameColorGenerator {
|
||||
private frameToColor = new Map<Frame, Color>()
|
||||
|
||||
|
172
flamechart-color-pass-renderer.ts
Normal file
172
flamechart-color-pass-renderer.ts
Normal file
@ -0,0 +1,172 @@
|
||||
import * as regl from 'regl'
|
||||
import { Vec2, Rect, AffineTransform } from './math'
|
||||
|
||||
export class FlamechartColorPassRenderProps {
|
||||
rectInfoTexture: regl.Texture
|
||||
renderOutlines: boolean
|
||||
srcRect: Rect
|
||||
dstRect: Rect
|
||||
}
|
||||
export class FlamechartColorPassRenderer {
|
||||
private command: regl.Command<FlamechartColorPassRenderProps>
|
||||
constructor(gl: regl.Instance) {
|
||||
this.command = gl({
|
||||
vert: `
|
||||
uniform mat3 uvTransform;
|
||||
uniform mat3 positionTransform;
|
||||
|
||||
attribute vec2 position;
|
||||
attribute vec2 uv;
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vUv = (uvTransform * vec3(uv, 1)).xy;
|
||||
gl_Position = vec4((positionTransform * vec3(position, 1)).xy, 0, 1);
|
||||
}
|
||||
`,
|
||||
|
||||
frag: `
|
||||
precision mediump float;
|
||||
|
||||
uniform vec2 uvSpacePixelSize;
|
||||
uniform float renderOutlines;
|
||||
|
||||
varying vec2 vUv;
|
||||
uniform sampler2D colorTexture;
|
||||
|
||||
// https://en.wikipedia.org/wiki/HSL_and_HSV#From_luma/chroma/hue
|
||||
vec3 lch2rgb(float L, float C, float H) {
|
||||
float hPrime = H / 60.0;
|
||||
float X = C * (1.0 - abs(mod(hPrime, 2.0) - 1.0));
|
||||
vec3 RGB =
|
||||
hPrime < 1.0 ? vec3(C, X, 0) :
|
||||
hPrime < 2.0 ? vec3(X, C, 0) :
|
||||
hPrime < 3.0 ? vec3(0, C, X) :
|
||||
hPrime < 4.0 ? vec3(0, X, C) :
|
||||
hPrime < 5.0 ? vec3(X, 0, C) :
|
||||
vec3(C, 0, X);
|
||||
|
||||
float m = L - dot(RGB, vec3(0.30, 0.59, 0.11));
|
||||
return RGB + vec3(m, m, m);
|
||||
}
|
||||
|
||||
vec3 colorForBucket(float bucket) {
|
||||
float x = 2.0 * fract(100.0 * bucket) - 1.0;
|
||||
float L = 0.85 - 0.1 * x;
|
||||
float C = 0.20 + 0.1 * x;
|
||||
float H = 360.0 * bucket;
|
||||
return lch2rgb(L, C, H);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 here = texture2D(colorTexture, vUv);
|
||||
|
||||
if (here.z == 0.0) {
|
||||
// Background color
|
||||
gl_FragColor = vec4(0, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Sample the 4 surrounding pixels in the depth texture to determine
|
||||
// if we should draw a boundary here or not.
|
||||
vec4 N = texture2D(colorTexture, vUv + vec2(0, uvSpacePixelSize.y));
|
||||
vec4 E = texture2D(colorTexture, vUv + vec2(uvSpacePixelSize.x, 0));
|
||||
vec4 S = texture2D(colorTexture, vUv + vec2(0, -uvSpacePixelSize.y));
|
||||
vec4 W = texture2D(colorTexture, vUv + vec2(-uvSpacePixelSize.x, 0));
|
||||
|
||||
// NOTE: For outline checks, we intentionally check both the right
|
||||
// and the left to determine if we're an edge. If a rectangle is a single
|
||||
// pixel wide, we don't want to render it as an outline, so this method
|
||||
// of checking ensures that we don't outline single physical-space
|
||||
// pixel width rectangles.
|
||||
if (
|
||||
renderOutlines > 0.0 &&
|
||||
(
|
||||
here.y == N.y && here.y != S.y || // Top edge
|
||||
here.y == S.y && here.y != N.y || // Bottom edge
|
||||
here.x == E.x && here.x != W.x || // Left edge
|
||||
here.x == W.x && here.x != E.x
|
||||
)
|
||||
) {
|
||||
// We're on an edge! Draw white.
|
||||
gl_FragColor = vec4(1, 1, 1, 1);
|
||||
} else {
|
||||
// Not on an edge. Draw the appropriate color;
|
||||
gl_FragColor = vec4(colorForBucket(here.z), here.a);
|
||||
}
|
||||
}
|
||||
`,
|
||||
|
||||
depth: {
|
||||
enable: false
|
||||
},
|
||||
|
||||
attributes: {
|
||||
// Cover full canvas with a rectangle
|
||||
// with 2 triangles using a triangle
|
||||
// strip.
|
||||
//
|
||||
// 0 +--+ 1
|
||||
// | /|
|
||||
// |/ |
|
||||
// 2 +--+ 3
|
||||
position: gl.buffer([
|
||||
[-1, 1],
|
||||
[1, 1],
|
||||
[-1, -1],
|
||||
[1, -1]
|
||||
]),
|
||||
uv: gl.buffer([
|
||||
[0, 1],
|
||||
[1, 1],
|
||||
[0, 0],
|
||||
[1, 0]
|
||||
])
|
||||
},
|
||||
|
||||
count: 4,
|
||||
|
||||
primitive: 'triangle strip',
|
||||
|
||||
uniforms: {
|
||||
colorTexture: (context, props) => props.rectInfoTexture,
|
||||
uvTransform: (context, props) => {
|
||||
const { srcRect, rectInfoTexture } = props
|
||||
const physicalToUV = AffineTransform.withTranslation(new Vec2(0, 1))
|
||||
.times(AffineTransform.withScale(new Vec2(1, -1)))
|
||||
.times(AffineTransform.betweenRects(
|
||||
new Rect(Vec2.zero, new Vec2(rectInfoTexture.width, rectInfoTexture.height)),
|
||||
Rect.unit
|
||||
))
|
||||
const uvRect = physicalToUV.transformRect(srcRect)
|
||||
return AffineTransform.betweenRects(
|
||||
Rect.unit,
|
||||
uvRect,
|
||||
).flatten()
|
||||
},
|
||||
renderOutlines: (context, props) => {
|
||||
return props.renderOutlines ? 1.0 : 0.0
|
||||
},
|
||||
uvSpacePixelSize: (context, props) => {
|
||||
return Vec2.unit.dividedByPointwise(new Vec2(props.rectInfoTexture.width, props.rectInfoTexture.height)).flatten()
|
||||
},
|
||||
positionTransform: (context, props) => {
|
||||
const { dstRect } = props
|
||||
const viewportSize = new Vec2(context.viewportWidth, context.viewportHeight)
|
||||
|
||||
const physicalToNDC = AffineTransform.withScale(new Vec2(1, -1))
|
||||
.times(AffineTransform.betweenRects(
|
||||
new Rect(Vec2.zero, viewportSize),
|
||||
Rect.NDC)
|
||||
)
|
||||
const ndcRect = physicalToNDC.transformRect(dstRect)
|
||||
return AffineTransform.betweenRects(Rect.NDC, ndcRect).flatten()
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
render(props: FlamechartColorPassRenderProps) {
|
||||
this.command(props)
|
||||
}
|
||||
}
|
@ -78,6 +78,10 @@ export class FlamechartMinimapView extends Component<FlamechartMinimapViewProps,
|
||||
}> | null = null
|
||||
private renderRects() {
|
||||
if (!this.container) return
|
||||
|
||||
// Hasn't resized yet -- no point in rendering yet
|
||||
if (this.physicalViewSize().x < 2) return
|
||||
|
||||
if (!this.cachedRenderer) {
|
||||
this.cachedRenderer = this.props.canvasContext.createTextureCachedRenderer({
|
||||
shouldUpdate(oldProps, newProps) {
|
||||
@ -93,15 +97,29 @@ export class FlamechartMinimapView extends Component<FlamechartMinimapViewProps,
|
||||
this.physicalViewSize().minus(this.minimapOrigin())
|
||||
),
|
||||
configSpaceSrcRect: new Rect(new Vec2(0, 0), this.configSpaceSize()),
|
||||
renderOutlines: false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.props.canvasContext.renderInto(this.container, (context) => {
|
||||
// TODO(jlfwong): Switch back to the texture cached renderer once I figure out
|
||||
// how to resize a framebuffer while another framebuffer is active. It seems
|
||||
// to crash regl. I should submit a reduced repro case and hopefully get it fixed?
|
||||
/*
|
||||
this.cachedRenderer!.render({
|
||||
physicalSize: this.physicalViewSize()
|
||||
})
|
||||
*/
|
||||
this.props.flamechartRenderer.render({
|
||||
configSpaceSrcRect: new Rect(new Vec2(0, 0), this.configSpaceSize()),
|
||||
physicalSpaceDstRect: new Rect(
|
||||
this.minimapOrigin(),
|
||||
this.physicalViewSize().minus(this.minimapOrigin())
|
||||
),
|
||||
renderOutlines: false
|
||||
})
|
||||
this.props.canvasContext.drawViewportRectangle({
|
||||
configSpaceViewportRect: this.props.configSpaceViewportRect,
|
||||
configSpaceToPhysicalViewSpace: this.configSpaceToPhysicalViewSpace(),
|
||||
|
@ -29,7 +29,7 @@ class RowAtlas<K> {
|
||||
framebuffer: this.framebuffer
|
||||
})
|
||||
this.clearLineBatch = canvasContext.createRectangleBatch()
|
||||
this.clearLineBatch.addRect(Rect.unit, new Color(1, 1, 1, 1))
|
||||
this.clearLineBatch.addRect(Rect.unit, new Color(0, 0, 0, 0))
|
||||
}
|
||||
|
||||
has(key: K) { return this.rowCache.has(key) }
|
||||
@ -169,6 +169,7 @@ class RangeTreeInteriorNode implements RangeTreeNode {
|
||||
export interface FlamechartRendererProps {
|
||||
configSpaceSrcRect: Rect
|
||||
physicalSpaceDstRect: Rect
|
||||
renderOutlines: boolean
|
||||
}
|
||||
|
||||
interface FlamechartRowAtlasKey {
|
||||
@ -180,8 +181,7 @@ interface FlamechartRowAtlasKey {
|
||||
export class FlamechartRenderer {
|
||||
private layers: RangeTreeNode[] = []
|
||||
private rowAtlas: RowAtlas<FlamechartRowAtlasKey>
|
||||
private colorTexture: regl.Texture
|
||||
private depthTexture: regl.Texture
|
||||
private rectInfoTexture: regl.Texture
|
||||
private framebuffer: regl.Framebuffer
|
||||
private renderToFramebuffer: regl.Command<{}>
|
||||
private withContext: regl.Command<{}>
|
||||
@ -199,7 +199,10 @@ export class FlamechartRenderer {
|
||||
|
||||
let rectCount = 0
|
||||
|
||||
for (let frame of flamechart.getLayers()[stackDepth]) {
|
||||
const layer = flamechart.getLayers()[stackDepth]
|
||||
|
||||
for (let i = 0; i < layer.length; i++) {
|
||||
const frame = layer[i]
|
||||
if (batch.getRectCount() >= MAX_BATCH_SIZE) {
|
||||
leafNodes.push(new RangeTreeLeafNode(batch, new Rect(
|
||||
new Vec2(minLeft, stackDepth),
|
||||
@ -215,7 +218,17 @@ export class FlamechartRenderer {
|
||||
)
|
||||
minLeft = Math.min(minLeft, configSpaceBounds.left())
|
||||
maxRight = Math.max(maxRight, configSpaceBounds.right())
|
||||
const color = flamechart.getColorForFrame(frame.node.frame)
|
||||
|
||||
// We'll use the red channel to indicate the index to allow
|
||||
// us to separate adjacent rectangles within a row from one another,
|
||||
// the green channel to indicate the row,
|
||||
// and the blue channel to indicate the color bucket to render.
|
||||
// We add one to each so we have zero reserved for the background color.
|
||||
const color = new Color(
|
||||
(1 + i % 255) / 256,
|
||||
(1 + stackDepth % 255) / 256,
|
||||
(1 + this.flamechart.getColorBucketForFrame(frame.node.frame)) / 256
|
||||
)
|
||||
batch.addRect(configSpaceBounds, color)
|
||||
rectCount++
|
||||
}
|
||||
@ -234,11 +247,9 @@ export class FlamechartRenderer {
|
||||
// TODO(jlfwong): Extract this to CanvasContext
|
||||
this.withContext = canvasContext.gl({})
|
||||
|
||||
this.colorTexture = this.canvasContext.gl.texture({ width: 1, height: 1 })
|
||||
this.depthTexture = this.canvasContext.gl.texture({ width: 1, height: 1, format: 'depth', type: 'uint16' })
|
||||
this.rectInfoTexture = this.canvasContext.gl.texture({ width: 1, height: 1 })
|
||||
this.framebuffer = this.canvasContext.gl.framebuffer({
|
||||
color: [this.colorTexture],
|
||||
depth: this.depthTexture
|
||||
color: [this.rectInfoTexture],
|
||||
})
|
||||
|
||||
this.renderToFramebuffer = canvasContext.gl({
|
||||
@ -352,22 +363,13 @@ export class FlamechartRenderer {
|
||||
}
|
||||
})
|
||||
|
||||
this.canvasContext.drawOutlines({
|
||||
colorTexture: this.colorTexture,
|
||||
depthTexture: this.depthTexture,
|
||||
srcRect: new Rect(Vec2.zero, new Vec2(this.colorTexture.width, this.colorTexture.height)),
|
||||
dstRect: physicalSpaceDstRect
|
||||
this.canvasContext.drawFlamechartColorPass({
|
||||
rectInfoTexture: this.rectInfoTexture,
|
||||
srcRect: new Rect(Vec2.zero, new Vec2(this.rectInfoTexture.width, this.rectInfoTexture.height)),
|
||||
dstRect: physicalSpaceDstRect,
|
||||
renderOutlines: props.renderOutlines
|
||||
})
|
||||
|
||||
// Paint the color texture for debugging
|
||||
/*
|
||||
this.canvasContext.drawTexture({
|
||||
texture: this.colorTexture,
|
||||
srcRect: new Rect(Vec2.zero, new Vec2(this.colorTexture.width, this.colorTexture.height)),
|
||||
dstRect: physicalSpaceDstRect
|
||||
})
|
||||
*/
|
||||
|
||||
// Overlay the atlas on top of the canvas for debugging
|
||||
/*
|
||||
this.canvasContext.drawTexture({
|
||||
|
@ -311,7 +311,8 @@ export class FlamechartPanZoomView extends ReloadableComponent<FlamechartPanZoom
|
||||
this.props.canvasContext.renderInto(this.container, (context) => {
|
||||
this.props.flamechartRenderer.render({
|
||||
physicalSpaceDstRect: new Rect(Vec2.zero, this.physicalViewSize()),
|
||||
configSpaceSrcRect: this.props.configSpaceViewportRect
|
||||
configSpaceSrcRect: this.props.configSpaceViewportRect,
|
||||
renderOutlines: true
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import {Frame, CallTreeNode} from './profile'
|
||||
import { Color } from './color'
|
||||
|
||||
import { lastOf } from './utils'
|
||||
|
||||
@ -23,7 +22,7 @@ interface FlamechartDataSource {
|
||||
closeFrame: (value: number) => void
|
||||
): void
|
||||
|
||||
getColorForFrame(f: Frame): Color
|
||||
getColorBucketForFrame(f: Frame): number
|
||||
}
|
||||
|
||||
export class Flamechart {
|
||||
@ -34,7 +33,7 @@ export class Flamechart {
|
||||
|
||||
getTotalWeight() { return this.totalWeight }
|
||||
getLayers() { return this.layers }
|
||||
getColorForFrame(f: Frame) { return this.source.getColorForFrame(f) }
|
||||
getColorBucketForFrame(frame: Frame) { return this.source.getColorBucketForFrame(frame) }
|
||||
getMinFrameWidth() { return this.minFrameWidth }
|
||||
formatValue(v: number) { return this.source.formatValue(v) }
|
||||
|
||||
|
@ -1,130 +0,0 @@
|
||||
import * as regl from 'regl'
|
||||
import { Vec2, Rect, AffineTransform } from './math'
|
||||
|
||||
export class OutlineRendererProps {
|
||||
colorTexture: regl.Texture
|
||||
depthTexture: regl.Texture
|
||||
srcRect: Rect
|
||||
dstRect: Rect
|
||||
}
|
||||
export class OutlineRenderer {
|
||||
private command: regl.Command<OutlineRendererProps>
|
||||
constructor(gl: regl.Instance) {
|
||||
this.command = gl({
|
||||
vert: `
|
||||
uniform mat3 uvTransform;
|
||||
uniform mat3 positionTransform;
|
||||
|
||||
attribute vec2 position;
|
||||
attribute vec2 uv;
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vUv = (uvTransform * vec3(uv, 1)).xy;
|
||||
gl_Position = vec4((positionTransform * vec3(position, 1)).xy, 0, 1);
|
||||
}
|
||||
`,
|
||||
|
||||
frag: `
|
||||
precision mediump float;
|
||||
|
||||
uniform vec2 uvSpacePixelSize;
|
||||
|
||||
varying vec2 vUv;
|
||||
uniform sampler2D colorTexture;
|
||||
uniform sampler2D depthTexture;
|
||||
|
||||
void main() {
|
||||
// Sample the 4 surrounding pixels in the depth texture to determine
|
||||
// if we should draw a boundary here or not.
|
||||
float N = texture2D(depthTexture, vUv + vec2(0, uvSpacePixelSize.y)).r;
|
||||
float E = texture2D(depthTexture, vUv + vec2(uvSpacePixelSize.x, 0)).r;
|
||||
float S = texture2D(depthTexture, vUv + vec2(0, -uvSpacePixelSize.y)).r;
|
||||
float W = texture2D(depthTexture, vUv + vec2(-uvSpacePixelSize.x, 0)).r;
|
||||
float here = texture2D(depthTexture, vUv).x;
|
||||
|
||||
if (
|
||||
here == N && here != S || // Top edge
|
||||
here == S && here != N || // Bottom edge
|
||||
here == E && here != W || // Left edge
|
||||
here == W && here != E
|
||||
) {
|
||||
// We're on an edge! Draw white.
|
||||
gl_FragColor = vec4(1, 1, 1, 1);
|
||||
} else {
|
||||
gl_FragColor = texture2D(colorTexture, vUv);
|
||||
}
|
||||
}
|
||||
`,
|
||||
|
||||
depth: {
|
||||
enable: false
|
||||
},
|
||||
|
||||
attributes: {
|
||||
// Cover full canvas with a rectangle
|
||||
// with 2 triangles using a triangle
|
||||
// strip.
|
||||
//
|
||||
// 0 +--+ 1
|
||||
// | /|
|
||||
// |/ |
|
||||
// 2 +--+ 3
|
||||
position: gl.buffer([
|
||||
[-1, 1],
|
||||
[1, 1],
|
||||
[-1, -1],
|
||||
[1, -1]
|
||||
]),
|
||||
uv: gl.buffer([
|
||||
[0, 1],
|
||||
[1, 1],
|
||||
[0, 0],
|
||||
[1, 0]
|
||||
])
|
||||
},
|
||||
|
||||
count: 4,
|
||||
|
||||
primitive: 'triangle strip',
|
||||
|
||||
uniforms: {
|
||||
colorTexture: (context, props) => props.colorTexture,
|
||||
depthTexture: (context, props) => props.depthTexture,
|
||||
uvTransform: (context, props) => {
|
||||
const { srcRect, colorTexture } = props
|
||||
const physicalToUV = AffineTransform.withTranslation(new Vec2(0, 1))
|
||||
.times(AffineTransform.withScale(new Vec2(1, -1)))
|
||||
.times(AffineTransform.betweenRects(
|
||||
new Rect(Vec2.zero, new Vec2(colorTexture.width, colorTexture.height)),
|
||||
Rect.unit
|
||||
))
|
||||
const uvRect = physicalToUV.transformRect(srcRect)
|
||||
return AffineTransform.betweenRects(
|
||||
Rect.unit,
|
||||
uvRect,
|
||||
).flatten()
|
||||
},
|
||||
uvSpacePixelSize: (context, props) => {
|
||||
return Vec2.unit.dividedByPointwise(new Vec2(props.colorTexture.width, props.colorTexture.height)).flatten()
|
||||
},
|
||||
positionTransform: (context, props) => {
|
||||
const { dstRect } = props
|
||||
const viewportSize = new Vec2(context.viewportWidth, context.viewportHeight)
|
||||
|
||||
const physicalToNDC = AffineTransform.withScale(new Vec2(1, -1))
|
||||
.times(AffineTransform.betweenRects(
|
||||
new Rect(Vec2.zero, viewportSize),
|
||||
Rect.NDC)
|
||||
)
|
||||
const ndcRect = physicalToNDC.transformRect(dstRect)
|
||||
return AffineTransform.betweenRects(Rect.NDC, ndcRect).flatten()
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
render(props: OutlineRendererProps) {
|
||||
this.command(props)
|
||||
}
|
||||
}
|
@ -32,21 +32,10 @@ export class RectangleBatch {
|
||||
return this.colorBuffer
|
||||
}
|
||||
|
||||
private indexBuffer: regl.Buffer | null = null
|
||||
getIndexBuffer() {
|
||||
if (!this.indexBuffer) {
|
||||
const indices = new Float32Array(this.rectCount)
|
||||
for (let i = 0; i < this.rectCount; i++) indices[i] = i
|
||||
this.indexBuffer = this.gl.buffer(indices)
|
||||
}
|
||||
return this.indexBuffer
|
||||
}
|
||||
|
||||
uploadToGPU() {
|
||||
this.getConfigSpaceOffsetBuffer()
|
||||
this.getConfigSpaceSizeBuffer()
|
||||
this.getColorBuffer()
|
||||
this.getIndexBuffer()
|
||||
}
|
||||
|
||||
addRect(rect: Rect, color: Color) {
|
||||
@ -89,16 +78,13 @@ export interface RectangleBatchRendererProps {
|
||||
export class RectangleBatchRenderer {
|
||||
private command: regl.Command<RectangleBatchRendererProps>
|
||||
constructor(gl: regl.Instance) {
|
||||
// We draw the parity / 4 into the depth channel so it
|
||||
// can be used in a post-processing step to draw boundaries
|
||||
// between rectangles. We use 4 different values (2 per row)
|
||||
// so we can distingish both between adjacent rectangles on a row
|
||||
// and between rows!
|
||||
// We draw the parity / 5 into the depth channel so it can be used in a
|
||||
// post-processing step to draw boundaries between rectangles. We use 5
|
||||
// different values (2 per row) + one for the background, so we can
|
||||
// distingish both between adjacent rectangles on a row and between rows!
|
||||
this.command = gl({
|
||||
vert: `
|
||||
uniform mat3 configSpaceToNDC;
|
||||
uniform float parityMin;
|
||||
uniform float parityOffset;
|
||||
|
||||
// Non-instanced
|
||||
attribute vec2 corner;
|
||||
@ -113,10 +99,9 @@ export class RectangleBatchRenderer {
|
||||
|
||||
void main() {
|
||||
vColor = color;
|
||||
float depth = parityMin + mod(parityOffset + index, 2.0);
|
||||
vec2 configSpacePos = configSpaceOffset + corner * configSpaceSize;
|
||||
vec2 position = (configSpaceToNDC * vec3(configSpacePos, 1)).xy;
|
||||
gl_Position = vec4(position, depth / 4.0, 1);
|
||||
gl_Position = vec4(position, 1, 1);
|
||||
}
|
||||
`,
|
||||
|
||||
@ -128,8 +113,9 @@ export class RectangleBatchRenderer {
|
||||
precision mediump float;
|
||||
varying vec3 vColor;
|
||||
varying float vParity;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = vec4(vColor, 1);
|
||||
gl_FragColor = vec4(vColor.rgb, 1);
|
||||
}
|
||||
`,
|
||||
|
||||
@ -169,15 +155,6 @@ export class RectangleBatchRenderer {
|
||||
size: 3,
|
||||
divisor: 1
|
||||
}
|
||||
},
|
||||
index: (context, props) => {
|
||||
return {
|
||||
buffer: props.batch.getIndexBuffer(),
|
||||
offset: 0,
|
||||
stride: 4,
|
||||
size: 1,
|
||||
divisor: 1
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -197,11 +174,11 @@ export class RectangleBatchRenderer {
|
||||
},
|
||||
|
||||
parityOffset: (context, props) => {
|
||||
return props.parityOffset || 0
|
||||
return props.parityOffset == null ? 0 : props.parityOffset
|
||||
},
|
||||
|
||||
parityMin: (context, props) => {
|
||||
return props.parityMin || 0
|
||||
return props.parityMin == null ? 0 : 1 + props.parityMin
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -155,10 +155,6 @@ export class TextureCachedRenderer<T> {
|
||||
}
|
||||
|
||||
if (needsRender) {
|
||||
// Render to texture
|
||||
// TODO(jlfwong): Re-enable this when I figure out how to
|
||||
// resize a framebuffer while another framebuffer is active.
|
||||
/*
|
||||
this.gl({
|
||||
viewport: (context, props) => {
|
||||
return {
|
||||
@ -173,7 +169,6 @@ export class TextureCachedRenderer<T> {
|
||||
this.gl.clear({color: [0, 0, 0, 0]})
|
||||
this.renderUncached(props)
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
const glViewportRect = new Rect(Vec2.zero, new Vec2(context.viewportWidth, context.viewportHeight))
|
||||
|
Loading…
Reference in New Issue
Block a user