Goal
- Run the canvas at 60FPS.
- Support real-time audio synthesis.
- Support running at 1ms per tick or less.
- Can we do 1000 computations per second or more?
- Identify what is blocking
- Support computation with a lot of machines
Caching Opcodes
- HashMap<u16, Op>; mapping between program counter and parsed opcode. No need to decode every time.
- Makes SMC impossible :(
Scheduler
- Machine Clock: machine should be able to execute on the fastest speed possible, but configurable to slow down execution.
- Audio: Schedule the audio at the right time. Uses Tone.js.
- note: do we need to consider AudioContext scheduler?
- Plotter: canvas 60 frames per second max.
- Clock: at the specified delay interval.
- React: should not render over 24 FPS.
Compute vs Audio
Technical
- Use
requestAnimationFrame
to tick every frame - better than usingsetTimeout
.
Poll versus Push
- Poll:
collect_audio_effects()
- Push:
add_audio_effects_callback(JsValue)
// Polling using schedulers on JavaScript side
Scheduler.on('audio', () => {
const fx = ctx.collect_audio_effects()
fx.forEach(handleAudioEffect)
})
// Pushing, using event listeners on the Rust side.
ctx.add_audio_effects_callback((messages) => {
})
Metrics to Profile
- Data transfer between JavaScript and Rust
- How the space complexity scales as we add large program and canvas modules.
- Mean tick time
- Tick time in JavaScript side
- Tick time in Rust/WebAssembly side
Optimization strategies
- Plotter: can we either send only the updated integers for JavaScript to reconcile, rather than sending the whole array of number every tick/frame?
- Concern: the diff-and-reconcile procedure might actually be slower than just sending over 100 integers across wasm!
Handling event loop and event listeners on Rust.
- Note that JS still has to call the Rust tick() function, as it can't sleep. Therefore, the JavaScript scheduler that wraps
requestAnimationFrame
must be implemented. - Can we batch ticks in Rust, then? For example, we tick an increment amount of frames
- Is doing it in Rust -> JS more efficient?
pub struct EventLoop {
audio: Vec<js_sys::Function>
}
impl EventLoop {
pub fn tick(&mut self) {
self.canvas.update()
}
}
Scheduler A: multiple loops at once
const FPS = 60
class Scheduler {
setup() {
requestAnimationFrame(this.updatePlotter)
}
updatePlotter() {
const diffs = ctx.collect_plot_diffs()
applyPlotDiffs(diffs)
requestAnimationFrame(this.updatePlotter)
}
}
Design notes for Visual Assembly Canvas