wasm: use requestAnimationFrame and report FPS.
This commit is contained in:
parent
82b8ff1c6a
commit
af54d4b95e
|
@ -33,14 +33,14 @@ Note that `run server` will automatically detect modification to
|
|||
|
||||
## Preliminary results:
|
||||
|
||||
* 2048x1024, draw1, release: 66.7ms
|
||||
* 2048x1024, draw2, release: 34.1ms ( 21.7ms / 12.4ms)
|
||||
* 2048x1024, draw3, release: 29.9ms ( 15.1ms / 14.8ms)
|
||||
* 2048x1024, draw1, release: 23 fps
|
||||
* 2048x1024, draw2, release: 51 fps
|
||||
* 2048x1024, draw3, release: 60 fps
|
||||
|
||||
* 1024x1024, draw1, release: 47.5ms
|
||||
* 1024x1024, draw2, release: 21.8ms ( 12.0ms / 9.8ms)
|
||||
* 1024x1024, draw3, release: 16.7ms ( 6.9ms / 9.8ms)
|
||||
* 1024x1024, draw1, release: 36 fps
|
||||
* 1024x1024, draw2, release: 60 fps
|
||||
* 1024x1024, draw3, release: 60 fps
|
||||
|
||||
* 1024x1024, draw1, debug: 376.6ms
|
||||
* 1024x1024, draw2, debug: 132.4ms (129.1ms / 3.3ms)
|
||||
* 1024x1024, draw3, debug: 131.4ms (128.8ms / 2.6ms)
|
||||
* 1024x1024, draw1, debug: 3 fps
|
||||
* 1024x1024, draw2, debug: 8 fps
|
||||
* 1024x1024, draw3, debug: 9 fps
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
||||
</head>
|
||||
<body>
|
||||
<button id="play-pause"></button>
|
||||
<pre id="fps">Frames per Second:</pre>
|
||||
<canvas id="target" width="400" height="400"></canvas>
|
||||
<script src='./bootstrap.js'></script>
|
||||
</body>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const WIDTH = 1024
|
||||
const WIDTH = 2048
|
||||
const HEIGHT = 1024
|
||||
const MODE = 3
|
||||
|
||||
|
@ -8,8 +8,8 @@ import { memory } from './novnc_bg'
|
|||
const canvas = document.getElementById('target')
|
||||
const ctx = canvas.getContext('2d')
|
||||
|
||||
canvas.width = WIDTH;
|
||||
canvas.height = HEIGHT;
|
||||
canvas.width = WIDTH
|
||||
canvas.height = HEIGHT
|
||||
|
||||
if (MODE === 2 || MODE === 3) {
|
||||
let byteSize = WIDTH * HEIGHT * 4
|
||||
|
@ -17,50 +17,98 @@ if (MODE === 2 || MODE === 3) {
|
|||
|
||||
var u8array = new Uint8ClampedArray(memory.buffer, pointer, byteSize)
|
||||
var imgData = new ImageData(u8array, WIDTH, HEIGHT)
|
||||
console.log("imgData:", imgData)
|
||||
}
|
||||
|
||||
let msList1 = []
|
||||
let msList2 = []
|
||||
let frame = -1
|
||||
|
||||
function avg(l) {
|
||||
return (l.reduce((a,b) => a+b, 0)/l.length).toFixed(2)
|
||||
}
|
||||
|
||||
function update() {
|
||||
let ms1, ms2
|
||||
function renderLoop() {
|
||||
const startMs = (new Date()).getTime()
|
||||
const red = parseInt(Math.random()*256)
|
||||
const green = parseInt(Math.random()*256)
|
||||
const blue = parseInt(Math.random()*256)
|
||||
console.log(`red: ${red}, green: ${green}, blue: ${blue}`)
|
||||
fps.render()
|
||||
frame += 1
|
||||
|
||||
if (MODE === 1) {
|
||||
novnc.draw1(ctx, WIDTH, HEIGHT,
|
||||
red, green, blue)
|
||||
ms1 = (new Date()).getTime()
|
||||
msList1.push(ms1 - startMs)
|
||||
console.log(`frame elapsed: ${ms1 - startMs} (${avg(msList1)})`)
|
||||
novnc.draw1(ctx, WIDTH, HEIGHT, frame)
|
||||
} else {
|
||||
if (MODE === 2) {
|
||||
novnc.draw2(pointer, WIDTH, HEIGHT,
|
||||
red, green, blue)
|
||||
novnc.draw2(pointer, WIDTH, HEIGHT, frame)
|
||||
} else if (MODE === 3) {
|
||||
novnc.draw3(pointer, WIDTH, HEIGHT,
|
||||
red, green, blue)
|
||||
novnc.draw3(pointer, WIDTH, HEIGHT, frame)
|
||||
}
|
||||
ms1 = (new Date()).getTime()
|
||||
ctx.putImageData(imgData, 0, 0)
|
||||
ms2 = (new Date()).getTime()
|
||||
msList1.push(ms1 - startMs)
|
||||
msList2.push(ms2 - ms1)
|
||||
console.log(`draw elapsed: ${ms1 - startMs} (${avg(msList1)}), ` +
|
||||
`putIMageData elapsed: ${ms2 - ms1} (${avg(msList2)})`)
|
||||
|
||||
//window.requestAnimationFrame(update)
|
||||
ctx.putImageData(imgData, 0, 0)
|
||||
}
|
||||
animationId = requestAnimationFrame(renderLoop)
|
||||
//console.log("elapsed:", (new Date()).getTime() - startMs)
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// From: https://github.com/rustwasm/wasm_game_of_life/blob/3253fa3a1557bdb9525f3b5c134b58efa1041c55/index.js#L27
|
||||
|
||||
let animationId = null
|
||||
|
||||
const fps = new class {
|
||||
constructor() {
|
||||
this.fps = document.getElementById("fps")
|
||||
this.frames = []
|
||||
this.lastFrameTimeStamp = performance.now()
|
||||
}
|
||||
|
||||
render() {
|
||||
const now = performance.now()
|
||||
const delta = now - this.lastFrameTimeStamp
|
||||
this.lastFrameTimeStamp = now
|
||||
const fps = 1 / delta * 1000
|
||||
|
||||
this.frames.push(fps)
|
||||
if (this.frames.length > 100) {
|
||||
this.frames.shift()
|
||||
}
|
||||
|
||||
let min = Infinity
|
||||
let max = -Infinity
|
||||
let sum = 0
|
||||
for (let i = 0; i < this.frames.length; i++) {
|
||||
sum += this.frames[i]
|
||||
min = Math.min(this.frames[i], min)
|
||||
max = Math.max(this.frames[i], max)
|
||||
}
|
||||
let mean = sum / this.frames.length
|
||||
|
||||
this.fps.textContent = `
|
||||
Frames per Second:
|
||||
latest = ${Math.round(fps)}
|
||||
avg of last 100 = ${Math.round(mean)}
|
||||
min of last 100 = ${Math.round(min)}
|
||||
max of last 100 = ${Math.round(max)}
|
||||
`.trim()
|
||||
}
|
||||
}
|
||||
|
||||
canvas.addEventListener('click', () => {
|
||||
update()
|
||||
const playPauseButton = document.getElementById("play-pause")
|
||||
|
||||
const isPaused = () => {
|
||||
return animationId === null
|
||||
}
|
||||
|
||||
const play = () => {
|
||||
playPauseButton.textContent = "⏸"
|
||||
renderLoop()
|
||||
}
|
||||
|
||||
const pause = () => {
|
||||
playPauseButton.textContent = "▶"
|
||||
cancelAnimationFrame(animationId)
|
||||
animationId = null
|
||||
}
|
||||
|
||||
playPauseButton.addEventListener("click", event => {
|
||||
if (isPaused()) {
|
||||
play()
|
||||
} else {
|
||||
pause()
|
||||
}
|
||||
})
|
||||
update()
|
||||
playPauseButton.textContent = "▶"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -34,14 +34,17 @@ extern "C" {
|
|||
pub fn put_image_data(this: &CanvasRenderingContext2D, image_data: &ImageData, p_1: i32, p_2: i32);
|
||||
}
|
||||
|
||||
pub fn fill(width: u32, height: u32, red: u8, green: u8, blue: u8) -> Vec<u8> {
|
||||
pub fn fill(width: u32, height: u32, frame: u32) -> Vec<u8> {
|
||||
let mut data: Vec<u8> = vec![];
|
||||
|
||||
for _x in 0..width {
|
||||
for _y in 0..height {
|
||||
data.push(red as u8);
|
||||
data.push(green as u8);
|
||||
data.push(blue as u8);
|
||||
for x in 0..width {
|
||||
for y in 0..height {
|
||||
let r = if (x%512) < 256 {x%256} else {255-(x%256)};
|
||||
let g = if (y%512) < 256 {y%256} else {255-(y%256)};
|
||||
let b = if (frame%512) < 256 {frame%256} else {255-(frame%256)};
|
||||
data.push(r as u8);
|
||||
data.push(g as u8);
|
||||
data.push(b as u8);
|
||||
data.push(255);
|
||||
}
|
||||
}
|
||||
|
@ -50,8 +53,8 @@ pub fn fill(width: u32, height: u32, red: u8, green: u8, blue: u8) -> Vec<u8> {
|
|||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn draw1(ctx: &CanvasRenderingContext2D, width: u32, height: u32, red: u8, green: u8, blue: u8) {
|
||||
let data = fill(width, height, red, green, blue);
|
||||
pub fn draw1(ctx: &CanvasRenderingContext2D, width: u32, height: u32, frame: u32) {
|
||||
let data = fill(width, height, frame);
|
||||
let uint8_array = Uint8ClampedArray::new(&data);
|
||||
|
||||
ctx.put_image_data(&ImageData::new(&uint8_array, width, height), 0, 0);
|
||||
|
@ -70,17 +73,20 @@ pub fn alloc(size: usize) -> *mut c_void {
|
|||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn draw2(mem: *mut u8, width: usize, height: usize, red: u8, green: u8, blue: u8) {
|
||||
pub fn draw2(mem: *mut u8, width: usize, height: usize, frame: u32) {
|
||||
|
||||
// pixels are stored in RGBA, so each pixel is 4 bytes
|
||||
let sl = unsafe { slice::from_raw_parts_mut(mem, width * height * 4) };
|
||||
|
||||
for y in 0..height {
|
||||
for x in 0..width {
|
||||
let r = if (x%512) < 256 {x%256} else {255-(x%256)};
|
||||
let g = if (y%512) < 256 {y%256} else {255-(y%256)};
|
||||
let b = if (frame%512) < 256 {frame%256} else {255-(frame%256)};
|
||||
let xy = x*4 + y*4*width;
|
||||
sl[xy + 0] = red;
|
||||
sl[xy + 1] = green;
|
||||
sl[xy + 2] = blue;
|
||||
sl[xy + 0] = r as u8;
|
||||
sl[xy + 1] = g as u8;
|
||||
sl[xy + 2] = b as u8;
|
||||
sl[xy + 3] = 255;
|
||||
}
|
||||
}
|
||||
|
@ -90,17 +96,20 @@ pub fn draw2(mem: *mut u8, width: usize, height: usize, red: u8, green: u8, blue
|
|||
/// draw3
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn draw3(mem: *mut u32, width: usize, height: usize, red: u8, green: u8, blue: u8) {
|
||||
pub fn draw3(mem: *mut u32, width: usize, height: usize, frame: u32) {
|
||||
|
||||
// pixels are stored in RGBA
|
||||
let sl = unsafe { slice::from_raw_parts_mut(mem, width * height) };
|
||||
|
||||
for y in 0..height {
|
||||
for x in 0..width {
|
||||
let r = if (x%512) < 256 {x%256} else {255-(x%256)};
|
||||
let g = if (y%512) < 256 {y%256} else {255-(y%256)};
|
||||
let b = if (frame%512) < 256 {frame%256} else {255-(frame%256)};
|
||||
let color = 0xff000000 |
|
||||
((blue as u32) << 16) |
|
||||
((green as u32) << 8) |
|
||||
((red as u32) << 0);
|
||||
(b << 16) |
|
||||
((g as u32) << 8) |
|
||||
((r as u32) << 0);
|
||||
sl[y*width + x] = color;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue