-
Notifications
You must be signed in to change notification settings - Fork 62
Expand file tree
/
Copy pathSceneRenderer.bench.ts
More file actions
71 lines (62 loc) · 3.12 KB
/
Copy pathSceneRenderer.bench.ts
File metadata and controls
71 lines (62 loc) · 3.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { server } from "@vitest/browser/context"
import { bench, describe } from "vitest"
import MirabufInstance from "@/mirabuf/MirabufInstance"
import MirabufParser from "@/mirabuf/MirabufParser"
import type { mirabuf } from "@/proto/mirabuf"
import SceneRenderer from "@/systems/scene/SceneRenderer"
import World from "@/systems/World"
import { getMiraAssembly } from "@/test/GetAssets"
const STANDARD_FRAME_DELTA = 1 / 60
// Top-level await: assemblies load once before any bench runs. beforeAll does not fire
// in Vitest browser bench mode (same workaround as the other .bench.ts files).
const [dozer, multiJoint, field2023] = (await Promise.all([
getMiraAssembly("DOZER"),
getMiraAssembly("MULTI_JOINT"),
getMiraAssembly(2023),
])) as [mirabuf.Assembly, mirabuf.Assembly, mirabuf.Assembly]
// MirabufInstance sets its materials up against World.sceneRenderer during construction,
// so a live World is required even though each scenario renders on its own SceneRenderer.
World.initWorld()
interface Scene {
renderer: SceneRenderer
gl: WebGLRenderingContext | WebGL2RenderingContext
}
// Build a standalone renderer with the given assemblies' geometry added directly to its
// scene. We bypass MirabufSceneObject/physics on purpose: this isolates the per-frame
// *render* cost (draw calls, shadow map, postprocessing) — what PerformanceMonitor reacts
// to and what dominates a real frame. Each scenario owns its own WebGL context so the
// scenes stay independent and directly comparable.
function makeScene(assemblies: mirabuf.Assembly[]): Scene {
const renderer = new SceneRenderer()
for (const assembly of assemblies) {
const instance = new MirabufInstance(new MirabufParser(assembly))
instance.addToScene(renderer.scene)
}
renderer.updateCanvasSize()
const gl = renderer.renderer.getContext()
// Warm up: the first frames compile shaders and allocate GPU buffers (hundreds of ms).
// Render a few and drain the GPU so that one-time cost never lands in a sample.
for (let i = 0; i < 5; i++) {
renderer.update(STANDARD_FRAME_DELTA)
gl.finish()
}
return { renderer, gl }
}
const empty = makeScene([])
const oneRobot = makeScene([dozer])
const robotAndField = makeScene([dozer, field2023])
const twoRobotsAndField = makeScene([dozer, multiJoint, field2023])
// composer.render() only queues GPU commands; gl.finish() blocks until they complete, so
// the timed region reflects the true frame cost instead of command-submission noise.
function renderFrame({ renderer, gl }: Scene) {
renderer.update(STANDARD_FRAME_DELTA)
gl.finish()
}
// Skip on firefox: WebGL is unreliable in the firefox instance under GitHub Actions
// (same guard as MirabufRealLoad.test.ts).
describe.skipIf(server.browser === "firefox")("SceneRenderer — full frame render", () => {
bench("render — empty scene (ground + skybox)", () => renderFrame(empty))
bench("render — 1 robot (Dozer)", () => renderFrame(oneRobot))
bench("render — 1 robot + field (2023)", () => renderFrame(robotAndField))
bench("render — 2 robots + field (2023)", () => renderFrame(twoRobotsAndField))
})