Skip to content

Commit d84d311

Browse files
authored
Add three.js benchmark (#75)
1 parent 553d3f7 commit d84d311

File tree

3 files changed

+31444
-3
lines changed

3 files changed

+31444
-3
lines changed

JetStreamDriver.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -969,7 +969,7 @@ class Benchmark {
969969
this.preloads = Object.entries(this.plan.preload ?? {});
970970
}
971971

972-
scoreIdentifiers() {
972+
scoreIdentifiers() {
973973
const ids = Object.keys(this.allScores()).map(name => this.scoreIdentifier(name));
974974
return ids;
975975
}
@@ -1913,6 +1913,15 @@ let BENCHMARKS = [
19131913
],
19141914
tags: ["Default", "Generators"],
19151915
}),
1916+
new DefaultBenchmark({
1917+
name: "threejs",
1918+
files: [
1919+
"./threejs/three.js",
1920+
"./threejs/benchmark.js",
1921+
],
1922+
deterministicRandom: true,
1923+
tags: ["Default", "ThreeJs"],
1924+
}),
19161925
// Wasm
19171926
new WasmEMCCBenchmark({
19181927
name: "HashSet-wasm",
@@ -2253,7 +2262,7 @@ let BENCHMARKS = [
22532262
"./WSL/WTrapError.js",
22542263
"./WSL/WTypeError.js",
22552264
"./WSL/WhileLoop.js",
2256-
"./WSL/WrapChecker.js",
2265+
"./WSL/WrapChecker.js",
22572266
"./WSL/Test.js",
22582267
],
22592268
tags: ["Default", "WSL"],
@@ -2374,7 +2383,7 @@ for (const benchmark of BENCHMARKS) {
23742383
throw new Error(`Duplicate benchmark with name "${name}}"`);
23752384
else
23762385
benchmarksByName.set(name, benchmark);
2377-
2386+
23782387
for (const tag of benchmark.tags) {
23792388
if (benchmarksByTag.has(tag))
23802389
benchmarksByTag.get(tag).push(benchmark);

threejs/benchmark.js

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
/*
2+
* Copyright (C) 2025 Mozilla. All rights reserved.
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions
6+
* are met:
7+
* 1. Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* 2. Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
*
13+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
14+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
17+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
23+
* POSSIBILITY OF SUCH DAMAGE.
24+
*/
25+
26+
const NUM_PARTICLES = 8000;
27+
28+
const scene = new THREE.Scene();
29+
scene.background = new THREE.Color(0x111111);
30+
31+
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
32+
const innerHeight = 1080;
33+
const innerWidth = 1920;
34+
camera.position.z = 500;
35+
36+
const canvas = {
37+
addEventListener() {},
38+
style: {},
39+
getContext(kind) {
40+
return {
41+
getExtension(extension) {
42+
if (extension == 'EXT_blend_minmax') {
43+
return {MIN_EXT: 32775, MAX_EXT: 32776}
44+
}
45+
if (extension == 'OES_vertex_array_object') {
46+
return {
47+
createVertexArrayOES() { return 1 },
48+
bindVertexArrayOES() {},
49+
deleteVertexArrayOES() {},
50+
}
51+
}
52+
},
53+
createTexture() {},
54+
bindTexture() {},
55+
texImage2D() {},
56+
texImage3D() {},
57+
texParameteri() {},
58+
uniform1i() {},
59+
uniform1f() {},
60+
uniform2f() {},
61+
uniform3f() {},
62+
uniform4f() {},
63+
clearColor() {},
64+
clear() {},
65+
clearDepth() {},
66+
clearStencil() {},
67+
enable() {},
68+
disable() {},
69+
depthFunc() {},
70+
depthMask() {},
71+
frontFace() {},
72+
cullFace() {},
73+
getContextAttributes() {},
74+
createBuffer() {},
75+
createFramebuffer() {},
76+
bindBuffer() {},
77+
bufferData() {},
78+
createProgram() {},
79+
attachShader() {},
80+
linkProgram() {},
81+
useProgram() {},
82+
getAttribLocation() {},
83+
getUniformLocation() {},
84+
createShader() {},
85+
shaderSource() {},
86+
compileShader() {},
87+
getShaderParameter() {},
88+
getProgramInfoLog() { return "" },
89+
getShaderInfoLog() { return "" },
90+
getProgramParameter() {},
91+
deleteShader() {},
92+
colorMask() {},
93+
stencilMask() {},
94+
createVertexArray() {},
95+
bindVertexArray() {},
96+
drawElements() {},
97+
lineWidth() {},
98+
drawArrays() {},
99+
viewport() {},
100+
getParameter(param) {
101+
if (param == 34930) { return 16 }
102+
if (param == 35660) { return 16 }
103+
if (param == 3379) { return 8192 }
104+
if (param == 36347) { return 1024 }
105+
if (param == 36348) { return 32 }
106+
if (param == 36349) { return 1024 }
107+
if (param == 35661) { return 80 }
108+
if (param == 7938) { return "WebGL 2.0" }
109+
if (param == 3088) { return [0,0,1024,480] }
110+
if (param == 2978) { return [0,0,1024,480] }
111+
},
112+
MAX_TEXTURE_IMAGE_UNITS: 34930,
113+
MAX_VERTEX_TEXTURE_IMAGE_UNITS: 35660,
114+
MAX_TEXTURE_SIZE: 3379,
115+
MAX_VERTEX_UNIFORM_VECTORS: 36347,
116+
MAX_VARYING_VECTORS: 36348,
117+
MAX_FRAGMENT_UNIFORM_VECTORS: 36349,
118+
MAX_COMBINED_TEXTURE_IMAGE_UNITS: 35661,
119+
VERSION: 7938,
120+
SCISSOR_BOX: 3088,
121+
VIEWPORT: 2978
122+
}
123+
}
124+
}
125+
126+
const renderer = new THREE.WebGLRenderer({
127+
antialias: false,
128+
canvas,
129+
powerPreference: 'low-power',
130+
precision: 'lowp'
131+
});
132+
renderer.setSize(innerWidth, innerHeight);
133+
134+
const createGeometryParticle = (size) => {
135+
const visibleHeight = 2 * Math.tan(75 * Math.PI/360) * 500;
136+
const radius = (size / innerHeight) * visibleHeight / 2;
137+
138+
// Main circle
139+
const geometry = new THREE.CircleGeometry(radius, 32);
140+
const material = new THREE.MeshBasicMaterial({
141+
color: 0xffffff,
142+
depthTest: false
143+
});
144+
const circle = new THREE.Mesh(geometry, material);
145+
146+
const posArray = geometry.attributes.position.array;
147+
const outlineVertices = [];
148+
for (let i = 3; i < posArray.length; i += 3) {
149+
outlineVertices.push(
150+
new THREE.Vector3(
151+
posArray[i],
152+
posArray[i + 1],
153+
posArray[i + 2]
154+
)
155+
);
156+
}
157+
const outlineGeometry = new THREE.BufferGeometry().setFromPoints(outlineVertices);
158+
const outline = new THREE.LineLoop(
159+
outlineGeometry,
160+
new THREE.LineBasicMaterial({ color: 0x000000, depthTest: false })
161+
);
162+
163+
const group = new THREE.Group();
164+
group.add(circle);
165+
group.add(outline);
166+
return group;
167+
};
168+
169+
// Initialize particles
170+
var initialized = false;
171+
const particles = [];
172+
173+
function initialize() {
174+
for(let i = 0; i < NUM_PARTICLES; i++) {
175+
const size = 10 + Math.random() * 80;
176+
const particle = createGeometryParticle(size);
177+
178+
// Random initial position
179+
const visibleWidth = 2 * Math.tan(75 * Math.PI/360) * 500 * camera.aspect;
180+
particle.position.set(
181+
THREE.MathUtils.randFloatSpread(visibleWidth),
182+
THREE.MathUtils.randFloatSpread(visibleWidth/camera.aspect),
183+
0
184+
);
185+
186+
// Velocity storage
187+
particle.velocity = new THREE.Vector2(
188+
(Math.random() - 0.5) * 8,
189+
(Math.random() - 0.5) * 8
190+
);
191+
192+
scene.add(particle);
193+
particles.push(particle);
194+
}
195+
initialized = true;
196+
}
197+
198+
// Metrics and animation
199+
const visibleWidth = 2 * Math.tan(75 * Math.PI/360) * 500 * camera.aspect;
200+
const visibleHeight = visibleWidth / camera.aspect;
201+
202+
function animate() {
203+
particles.forEach(particle => {
204+
particle.position.x += particle.velocity.x;
205+
particle.position.y += particle.velocity.y;
206+
207+
// Boundary checks
208+
if(Math.abs(particle.position.x) > visibleWidth/2)
209+
particle.velocity.x *= -1;
210+
if(Math.abs(particle.position.y) > visibleHeight/2)
211+
particle.velocity.y *= -1;
212+
});
213+
214+
renderer.render(scene, camera);
215+
}
216+
217+
class Benchmark {
218+
runIteration() {
219+
if (!initialized) {
220+
initialize();
221+
}
222+
animate();
223+
}
224+
}

0 commit comments

Comments
 (0)