mirror of
https://github.com/jlfwong/speedscope.git
synced 2024-11-22 12:53:23 +03:00
1987e83bde
Previously, I was doing a hacky release process where I had `index.html` serve contents for `jlfwong.github.io/speedscope`, but used `dev.html` locally. This seems like it broke with the latest parcel release, so I just revamped the release process instead. Now, the `release.sh` script creates a temporary shallow clone of the repository, overwrites its contents with build artifacts, runs a local server to verify it's working, then commits and pushes to the `gh-pages` branches.
201 lines
5.7 KiB
TypeScript
201 lines
5.7 KiB
TypeScript
import regl from 'regl'
|
|
import { Rect, Vec2, AffineTransform } from './math'
|
|
import { Color } from './color'
|
|
|
|
export class RectangleBatch {
|
|
private rectCapacity = 1000
|
|
private rectCount = 0
|
|
|
|
private configSpaceOffsets = new Float32Array(this.rectCapacity * 2)
|
|
private configSpaceSizes = new Float32Array(this.rectCapacity * 2)
|
|
private colors = new Float32Array(this.rectCapacity * 3)
|
|
|
|
constructor(private gl: regl.Instance) { }
|
|
|
|
getRectCount() { return this.rectCount }
|
|
|
|
private configSpaceOffsetBuffer: regl.Buffer | null = null
|
|
getConfigSpaceOffsetBuffer() {
|
|
if (!this.configSpaceOffsetBuffer) this.configSpaceOffsetBuffer = this.gl.buffer(this.configSpaceOffsets)
|
|
return this.configSpaceOffsetBuffer
|
|
}
|
|
|
|
private configSpaceSizeBuffer: regl.Buffer | null = null
|
|
getConfigSpaceSizeBuffer() {
|
|
if (!this.configSpaceSizeBuffer) this.configSpaceSizeBuffer = this.gl.buffer(this.configSpaceSizes)
|
|
return this.configSpaceSizeBuffer
|
|
}
|
|
|
|
private colorBuffer: regl.Buffer | null = null
|
|
getColorBuffer() {
|
|
if (!this.colorBuffer) this.colorBuffer = this.gl.buffer(this.colors)
|
|
return this.colorBuffer
|
|
}
|
|
|
|
uploadToGPU() {
|
|
this.getConfigSpaceOffsetBuffer()
|
|
this.getConfigSpaceSizeBuffer()
|
|
this.getColorBuffer()
|
|
}
|
|
|
|
addRect(rect: Rect, color: Color) {
|
|
const index = this.rectCount++
|
|
if (index >= this.rectCapacity) {
|
|
// Not enough capacity, time to resize! We'll double the capacity each time.
|
|
this.rectCapacity *= 2
|
|
const configSpaceOffsets = new Float32Array(this.rectCapacity * 2)
|
|
const configSpaceSizes = new Float32Array(this.rectCapacity * 2)
|
|
const colors = new Float32Array(this.rectCapacity * 3)
|
|
|
|
configSpaceOffsets.set(this.configSpaceOffsets)
|
|
configSpaceSizes.set(this.configSpaceSizes)
|
|
colors.set(this.colors)
|
|
|
|
this.configSpaceOffsets = configSpaceOffsets
|
|
this.configSpaceSizes = configSpaceSizes
|
|
this.colors = colors
|
|
}
|
|
this.configSpaceOffsets[index * 2] = rect.origin.x
|
|
this.configSpaceOffsets[index * 2 + 1] = rect.origin.y
|
|
|
|
this.configSpaceSizes[index * 2] = rect.size.x
|
|
this.configSpaceSizes[index * 2 + 1] = rect.size.y
|
|
|
|
this.colors[index * 3] = color.r
|
|
this.colors[index * 3 + 1] = color.g
|
|
this.colors[index * 3 + 2] = color.b
|
|
}
|
|
}
|
|
|
|
export interface RectangleBatchRendererProps {
|
|
batch: RectangleBatch
|
|
configSpaceSrcRect: Rect
|
|
physicalSpaceDstRect: Rect
|
|
parityMin?: number
|
|
parityOffset?: number
|
|
}
|
|
|
|
export class RectangleBatchRenderer {
|
|
private command: regl.Command<RectangleBatchRendererProps>
|
|
constructor(gl: regl.Instance) {
|
|
// 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;
|
|
|
|
// Non-instanced
|
|
attribute vec2 corner;
|
|
|
|
// Instanced
|
|
attribute vec2 configSpaceOffset;
|
|
attribute vec2 configSpaceSize;
|
|
attribute vec3 color;
|
|
attribute float index;
|
|
|
|
varying vec3 vColor;
|
|
|
|
void main() {
|
|
vColor = color;
|
|
vec2 configSpacePos = configSpaceOffset + corner * configSpaceSize;
|
|
vec2 position = (configSpaceToNDC * vec3(configSpacePos, 1)).xy;
|
|
gl_Position = vec4(position, 1, 1);
|
|
}
|
|
`,
|
|
|
|
depth: {
|
|
enable: false
|
|
},
|
|
|
|
frag: `
|
|
precision mediump float;
|
|
varying vec3 vColor;
|
|
varying float vParity;
|
|
|
|
void main() {
|
|
gl_FragColor = vec4(vColor.rgb, 1);
|
|
}
|
|
`,
|
|
|
|
attributes: {
|
|
// Non-instanced attributes
|
|
corner: gl.buffer([
|
|
[0, 0],
|
|
[1, 0],
|
|
[0, 1],
|
|
[1, 1],
|
|
]),
|
|
|
|
// Instanced attributes
|
|
configSpaceOffset: (context, props) => {
|
|
return {
|
|
buffer: props.batch.getConfigSpaceOffsetBuffer(),
|
|
offset: 0,
|
|
stride: 2 * 4,
|
|
size: 2,
|
|
divisor: 1
|
|
}
|
|
},
|
|
configSpaceSize: (context, props) => {
|
|
return {
|
|
buffer: props.batch.getConfigSpaceSizeBuffer(),
|
|
offset: 0,
|
|
stride: 2 * 4,
|
|
size: 2,
|
|
divisor: 1
|
|
}
|
|
},
|
|
color: (context, props) => {
|
|
return {
|
|
buffer: props.batch.getColorBuffer(),
|
|
offset: 0,
|
|
stride: 3 * 4,
|
|
size: 3,
|
|
divisor: 1
|
|
}
|
|
}
|
|
},
|
|
|
|
uniforms: {
|
|
configSpaceToNDC: (context, props) => {
|
|
const configToPhysical = AffineTransform.betweenRects(
|
|
props.configSpaceSrcRect,
|
|
props.physicalSpaceDstRect
|
|
)
|
|
|
|
const viewportSize = new Vec2(context.viewportWidth, context.viewportHeight)
|
|
|
|
const physicalToNDC = AffineTransform.withTranslation(new Vec2(-1, 1))
|
|
.times(AffineTransform.withScale(new Vec2(2, -2).dividedByPointwise(viewportSize)))
|
|
|
|
return physicalToNDC.times(configToPhysical).flatten()
|
|
},
|
|
|
|
parityOffset: (context, props) => {
|
|
return props.parityOffset == null ? 0 : props.parityOffset
|
|
},
|
|
|
|
parityMin: (context, props) => {
|
|
return props.parityMin == null ? 0 : 1 + props.parityMin
|
|
}
|
|
},
|
|
|
|
instances: (context, props) => {
|
|
return props.batch.getRectCount()
|
|
},
|
|
|
|
count: 4,
|
|
|
|
primitive: 'triangle strip',
|
|
})
|
|
}
|
|
|
|
render(props: RectangleBatchRendererProps) {
|
|
this.command(props)
|
|
}
|
|
|
|
resetStats() { return Object.assign(this.command.stats, { cpuTime: 0, gpuTime: 0, count: 0 }) }
|
|
stats() { return this.command.stats }
|
|
} |