xbintsc 0.5.37 → 0.5.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cli/help.d.ts +1 -1
- package/dist/src/codegen/generator/module.js +23 -7
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.js +1 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.js +1 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/deferred.d.ts +63 -0
- package/dist/src/driver/bundler/deferred.js +279 -0
- package/dist/src/driver/bundler/deferred.js.map +1 -0
- package/dist/src/driver/bundler/merge.js +214 -2
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/runtime-objects.d.ts +1 -1
- package/dist/src/driver/runtime-objects.js +1 -0
- package/dist/src/driver/runtime-objects.js.map +1 -1
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/gui/html.js +98 -15
- package/dist/src/extensions/gui/html.js.map +1 -1
- package/dist/src/extensions/gui/index.js +1 -0
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/gui/three.d.ts +4 -3
- package/dist/src/extensions/gui/three.js +4 -3
- package/dist/src/extensions/gui/three.js.map +1 -1
- package/dist/tests/codegen/closures.test.js +7 -0
- package/dist/tests/codegen/closures.test.js.map +1 -1
- package/dist/tests/e2e/compile-objects-classes.test.js +31 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
- package/dist/tests/e2e/gui-canvas-state.test.d.ts +9 -0
- package/dist/tests/e2e/gui-canvas-state.test.js +297 -0
- package/dist/tests/e2e/gui-canvas-state.test.js.map +1 -0
- package/dist/tests/e2e/gui-draw-perf.test.d.ts +22 -0
- package/dist/tests/e2e/gui-draw-perf.test.js +405 -0
- package/dist/tests/e2e/gui-draw-perf.test.js.map +1 -0
- package/dist/tests/e2e/gui-perf.test.d.ts +23 -0
- package/dist/tests/e2e/gui-perf.test.js +283 -0
- package/dist/tests/e2e/gui-perf.test.js.map +1 -0
- package/dist/tests/e2e/gui-script-import-order.test.d.ts +10 -0
- package/dist/tests/e2e/gui-script-import-order.test.js +169 -0
- package/dist/tests/e2e/gui-script-import-order.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl.test.js +4 -4
- package/dist/tests/e2e/gui-webgl.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.d.ts +8 -0
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.js +336 -0
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.d.ts +10 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.js +108 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.js.map +1 -0
- package/dist/tests/e2e/url.test.d.ts +6 -0
- package/dist/tests/e2e/url.test.js +114 -0
- package/dist/tests/e2e/url.test.js.map +1 -0
- package/dist/tests/extensions/gui.test.js +45 -10
- package/dist/tests/extensions/gui.test.js.map +1 -1
- package/doc/gui/api.md +28 -2
- package/doc/gui/canvas.md +110 -27
- package/doc/gui/known-issues.md +32 -10
- package/doc/gui/rendering.md +77 -0
- package/doc/gui/runtime.md +18 -3
- package/doc/gui/webgl.md +58 -29
- package/doc/gui-scripts.md +19 -19
- package/doc/gui.md +43 -9
- package/doc/implemented/fetch.md +5 -0
- package/doc/implemented/modules.md +13 -0
- package/doc/implemented/stdlib.md +17 -0
- package/doc/unimplemented/deviations.md +1 -0
- package/doc/zh-CN/gui/api.md +25 -2
- package/doc/zh-CN/gui/canvas.md +95 -26
- package/doc/zh-CN/gui/known-issues.md +21 -4
- package/doc/zh-CN/gui/rendering.md +59 -0
- package/doc/zh-CN/gui/runtime.md +13 -3
- package/doc/zh-CN/gui/webgl.md +30 -8
- package/doc/zh-CN/gui-scripts.md +14 -13
- package/doc/zh-CN/gui.md +32 -8
- package/doc/zh-CN/implemented/fetch.md +4 -0
- package/doc/zh-CN/implemented/modules.md +10 -0
- package/doc/zh-CN/implemented/stdlib.md +15 -0
- package/doc/zh-CN/unimplemented/deviations.md +1 -0
- package/package.json +7 -7
- package/runtime/ext_gui/browser.cpp +3 -1
- package/runtime/ext_gui/canvas.cpp +135 -89
- package/runtime/ext_gui/canvas.h +116 -0
- package/runtime/ext_gui/canvas_clip.cpp +143 -0
- package/runtime/ext_gui/canvas_composite.cpp +241 -0
- package/runtime/ext_gui/canvas_coverage.cpp +241 -0
- package/runtime/ext_gui/canvas_gradient.cpp +41 -4
- package/runtime/ext_gui/canvas_image_data.cpp +4 -0
- package/runtime/ext_gui/canvas_internal.h +34 -9
- package/runtime/ext_gui/canvas_raster.cpp +207 -178
- package/runtime/ext_gui/canvas_shadow.cpp +161 -0
- package/runtime/ext_gui/canvas_stroke.cpp +37 -9
- package/runtime/ext_gui/canvas_style.cpp +59 -0
- package/runtime/ext_gui/canvas_text.cpp +140 -0
- package/runtime/ext_gui/css.h +7 -0
- package/runtime/ext_gui/css_sheet.cpp +22 -0
- package/runtime/ext_gui/document.cpp +25 -1
- package/runtime/ext_gui/document.h +8 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +16 -1
- package/runtime/ext_gui/dom_api_canvas_image.cpp +9 -0
- package/runtime/ext_gui/dom_api_canvas_state.cpp +217 -0
- package/runtime/ext_gui/dom_api_internal.h +36 -37
- package/runtime/ext_gui/dom_api_offscreen.cpp +213 -0
- package/runtime/ext_gui/dom_api_proto.cpp +18 -0
- package/runtime/ext_gui/dom_api_webgl.cpp +29 -9
- package/runtime/ext_gui/dom_api_webgl2.cpp +33 -1
- package/runtime/ext_gui/dom_api_webgl_internal.h +58 -0
- package/runtime/ext_gui/dom_api_webgl_source.cpp +18 -0
- package/runtime/ext_gui/gradient_values.cpp +12 -1
- package/runtime/ext_gui/gui.cpp +5 -0
- package/runtime/ext_gui/gui_canvas.cpp +4 -0
- package/runtime/ext_gui/gui_engine.h +32 -0
- package/runtime/ext_gui/gui_events.cpp +182 -58
- package/runtime/ext_gui/gui_media.cpp +3 -0
- package/runtime/ext_gui/image.cpp +69 -0
- package/runtime/ext_gui/image_bitmap_browser.cpp +11 -0
- package/runtime/ext_gui/layout.cpp +4 -0
- package/runtime/ext_gui/paint.cpp +19 -0
- package/runtime/ext_gui/paint_background.cpp +18 -1
- package/runtime/ext_gui/perf.cpp +171 -0
- package/runtime/ext_gui/perf.h +127 -0
- package/runtime/ext_gui/renderer.cpp +109 -41
- package/runtime/ext_gui/renderer.h +33 -9
- package/runtime/ext_gui/renderer_image.cpp +135 -65
- package/runtime/ext_gui/renderer_internal.h +15 -3
- package/runtime/ext_gui/renderer_text.cpp +24 -12
- package/runtime/ext_gui/script.cpp +31 -0
- package/runtime/ext_gui/style.cpp +101 -30
- package/runtime/ext_gui/style.h +6 -3
- package/runtime/ext_gui/style_print.cpp +7 -1
- package/runtime/ext_gui/text.cpp +23 -4
- package/runtime/ext_gui/text.h +29 -0
- package/runtime/ext_gui/text_cache.cpp +118 -0
- package/runtime/ext_gui/text_glyph_cache.cpp +100 -0
- package/runtime/ext_gui/webgl.h +48 -146
- package/runtime/ext_gui/webgl_blit.cpp +12 -1
- package/runtime/ext_gui/webgl_blit_depth.cpp +270 -0
- package/runtime/ext_gui/webgl_buffer.cpp +59 -1
- package/runtime/ext_gui/webgl_buffer_objects.cpp +106 -9
- package/runtime/ext_gui/webgl_clear.cpp +3 -0
- package/runtime/ext_gui/webgl_context.cpp +29 -3
- package/runtime/ext_gui/webgl_draw.cpp +75 -270
- package/runtime/ext_gui/webgl_draw_buffers.cpp +1 -0
- package/runtime/ext_gui/webgl_draw_setup.cpp +321 -0
- package/runtime/ext_gui/webgl_draw_state.h +130 -0
- package/runtime/ext_gui/webgl_glsl.h +3 -0
- package/runtime/ext_gui/webgl_glsl_scan.cpp +3 -8
- package/runtime/ext_gui/webgl_glsl_unroll.cpp +283 -0
- package/runtime/ext_gui/webgl_msl.cpp +4 -0
- package/runtime/ext_gui/webgl_objects.h +148 -0
- package/runtime/ext_gui/webgl_pipeline.cpp +8 -8
- package/runtime/ext_gui/webgl_program_internal.h +35 -0
- package/runtime/ext_gui/webgl_shader.cpp +34 -36
- package/runtime/ext_gui/webgl_webgl2.cpp +36 -0
- package/runtime/ext_gui/window.cpp +56 -1
- package/runtime/rt.h +3 -0
- package/runtime/xt_fetch/async.inc +60 -0
- package/runtime/xt_url_object.c +463 -0
- package/src/codegen/generator/module.ts +22 -7
- package/src/codegen/generator/state.ts +1 -0
- package/src/codegen/generator/tables.ts +1 -0
- package/src/driver/bundler/deferred.ts +351 -0
- package/src/driver/bundler/merge.ts +219 -2
- package/src/driver/runtime-objects.ts +1 -0
- package/src/driver/version.ts +1 -1
- package/src/extensions/gui/html.ts +100 -17
- package/src/extensions/gui/index.ts +1 -0
- package/src/extensions/gui/three.ts +4 -3
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end benchmark for the two immediate-mode drawing surfaces.
|
|
3
|
+
*
|
|
4
|
+
* The `gui-perf` suite measures the retained DOM pipeline (restyle/layout/paint
|
|
5
|
+
* runs). This one measures the two APIs a multi-element scene actually calls
|
|
6
|
+
* thousands of times per frame:
|
|
7
|
+
*
|
|
8
|
+
* - `<canvas>` 2D: solid `fillRect`, multi-segment `stroke`, repeated
|
|
9
|
+
* `fillText` and 1:1 `drawImage`, drawn into a 1280x720 bitmap;
|
|
10
|
+
* - WebGL: 2000 `drawElements` calls with a per-draw matrix, plus a 64 KB
|
|
11
|
+
* `bufferSubData` into a 4 MB buffer.
|
|
12
|
+
*
|
|
13
|
+
* The programs print wall-clock milliseconds per scene (informational: CI may
|
|
14
|
+
* run on a software GPU) and the engine counters that a regression would move:
|
|
15
|
+
* `canvasDraws`/`canvasUploads`/`canvasUploadBytes` and
|
|
16
|
+
* `webglDraws`/`webglPasses`/`webglPipelineMisses`/`webglBufferUploadBytes`
|
|
17
|
+
* from `win.stats()` (see `runtime/ext_gui/perf.h`).
|
|
18
|
+
*
|
|
19
|
+
* The counters are asserted (deterministic). Timings are printed and, on a
|
|
20
|
+
* developer machine, can be bounded with `XBINTSC_GUI_DRAW_PERF_STRICT_MS`.
|
|
21
|
+
*/
|
|
22
|
+
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
23
|
+
import { createGuiHarness, guiAvailable } from "./gui-helpers.js";
|
|
24
|
+
const harness = createGuiHarness();
|
|
25
|
+
/** Frames each scene runs after the first (which does the one-time GPU work). */
|
|
26
|
+
const FRAMES = 16;
|
|
27
|
+
/** Parse `bench.<name> key=value …` lines into numbers. */
|
|
28
|
+
function parseBenches(stdout) {
|
|
29
|
+
const benches = {};
|
|
30
|
+
for (const line of stdout.split("\n")) {
|
|
31
|
+
const match = /^bench\.([a-z0-9]+)[ \t]+(.*)$/.exec(line);
|
|
32
|
+
if (match === null)
|
|
33
|
+
continue;
|
|
34
|
+
const name = match[1];
|
|
35
|
+
const rest = match[2];
|
|
36
|
+
if (name === undefined || rest === undefined)
|
|
37
|
+
continue;
|
|
38
|
+
const fields = {};
|
|
39
|
+
for (const token of rest.split(/\s+/)) {
|
|
40
|
+
const equals = token.indexOf("=");
|
|
41
|
+
if (equals <= 0)
|
|
42
|
+
continue;
|
|
43
|
+
const value = Number(token.slice(equals + 1));
|
|
44
|
+
if (!Number.isNaN(value))
|
|
45
|
+
fields[token.slice(0, equals)] = value;
|
|
46
|
+
}
|
|
47
|
+
/* A line like `bench.webgl unsupported` carries no fields; do not let it
|
|
48
|
+
* replace the sample line of the same scene. */
|
|
49
|
+
if (Object.keys(fields).length === 0)
|
|
50
|
+
continue;
|
|
51
|
+
benches[name] = fields;
|
|
52
|
+
}
|
|
53
|
+
return benches;
|
|
54
|
+
}
|
|
55
|
+
function field(benches, bench, key) {
|
|
56
|
+
const fields = benches[bench];
|
|
57
|
+
if (fields === undefined)
|
|
58
|
+
throw new Error(`missing bench.${bench} line in the program output`);
|
|
59
|
+
const value = fields[key];
|
|
60
|
+
if (value === undefined)
|
|
61
|
+
throw new Error(`missing bench.${bench}.${key}`);
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
/** Optional wall-clock budget for the canvas scene, in milliseconds per frame. */
|
|
65
|
+
function strictMs() {
|
|
66
|
+
return Number(process.env.XBINTSC_GUI_DRAW_PERF_STRICT_MS ?? "0");
|
|
67
|
+
}
|
|
68
|
+
describe.skipIf(!guiAvailable)("gui extension — immediate-mode draw performance", () => {
|
|
69
|
+
beforeAll(() => harness.setup());
|
|
70
|
+
afterAll(() => harness.cleanup());
|
|
71
|
+
it("draws many canvas primitives with bounded per-element overhead", () => {
|
|
72
|
+
const result = harness.compileAndRun("drawbench-canvas", `
|
|
73
|
+
import { createWindow, run } from "gui";
|
|
74
|
+
|
|
75
|
+
const W = 1280;
|
|
76
|
+
const H = 720;
|
|
77
|
+
const FRAMES = ${FRAMES};
|
|
78
|
+
|
|
79
|
+
const HTML = "<html><head><style>body { margin: 0; }</style></head><body>" +
|
|
80
|
+
"<canvas id='c' width='" + W + "' height='" + H + "'></canvas>" +
|
|
81
|
+
"<canvas id='s' width='32' height='32'></canvas></body></html>";
|
|
82
|
+
|
|
83
|
+
const win = createWindow({ title: "drawbench-canvas", width: 900, height: 700 });
|
|
84
|
+
win.loadHTML(HTML);
|
|
85
|
+
|
|
86
|
+
const round = (value: number): number => Math.round(value * 100) / 100;
|
|
87
|
+
const colors = [
|
|
88
|
+
"#ffffff", "#ff0000", "#00ff00", "#0000ff",
|
|
89
|
+
"#ffff00", "#00ffff", "#ff00ff", "#888888",
|
|
90
|
+
"#ff8800", "#88ff00", "#0088ff", "#ff0088",
|
|
91
|
+
"#440000", "#004400", "#000044", "#cccccc",
|
|
92
|
+
];
|
|
93
|
+
const labels = [
|
|
94
|
+
"alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
|
|
95
|
+
"india", "juliet", "kilo", "lima", "mike", "november", "oscar", "papa",
|
|
96
|
+
"quebec", "romeo", "sierra", "tango", "uniform", "victor", "whiskey", "xray",
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
/** Deterministic LCG so every run draws the same scene. */
|
|
100
|
+
let seed = 12345;
|
|
101
|
+
const rnd = (): number => {
|
|
102
|
+
seed = (seed * 1103515245 + 12345) % 2147483648;
|
|
103
|
+
return seed / 2147483648;
|
|
104
|
+
};
|
|
105
|
+
const at = (span: number): number => Math.floor(rnd() * span);
|
|
106
|
+
|
|
107
|
+
const canvas: any = win.document.getElementById("c");
|
|
108
|
+
const ctx: any = canvas.getContext("2d");
|
|
109
|
+
const sprite: any = win.document.getElementById("s");
|
|
110
|
+
const sctx: any = sprite.getContext("2d");
|
|
111
|
+
sctx.fillStyle = "#88ccff";
|
|
112
|
+
sctx.fillRect(0, 0, 32, 32);
|
|
113
|
+
|
|
114
|
+
const scene = (): void => {
|
|
115
|
+
const fillStart = performance.now();
|
|
116
|
+
/* 5000 small solid rectangles, a different colour per element. */
|
|
117
|
+
for (let i = 0; i < 5000; i++) {
|
|
118
|
+
ctx.fillStyle = colors[i % 16];
|
|
119
|
+
ctx.fillRect(at(W - 8), at(H - 8), 8, 8);
|
|
120
|
+
}
|
|
121
|
+
const strokeStart = performance.now();
|
|
122
|
+
/* 200 polylines of 8 points each (1400 segments). */
|
|
123
|
+
ctx.strokeStyle = "#3399ff";
|
|
124
|
+
ctx.lineWidth = 2;
|
|
125
|
+
for (let p = 0; p < 200; p++) {
|
|
126
|
+
ctx.beginPath();
|
|
127
|
+
ctx.moveTo(at(W), at(H));
|
|
128
|
+
for (let k = 0; k < 7; k++) ctx.lineTo(at(W), at(H));
|
|
129
|
+
ctx.stroke();
|
|
130
|
+
}
|
|
131
|
+
const textStart = performance.now();
|
|
132
|
+
/* 300 text runs reusing 24 labels, so shape/glyph caches can hit. */
|
|
133
|
+
ctx.font = "12px sans-serif";
|
|
134
|
+
ctx.fillStyle = "#eeeeee";
|
|
135
|
+
for (let t = 0; t < 300; t++) {
|
|
136
|
+
ctx.fillText(labels[t % 24], at(W - 120), at(H - 20));
|
|
137
|
+
}
|
|
138
|
+
const imageStart = performance.now();
|
|
139
|
+
/* 200 1:1 sprite blits. */
|
|
140
|
+
for (let im = 0; im < 200; im++) {
|
|
141
|
+
ctx.drawImage(sprite, at(W - 32), at(H - 32));
|
|
142
|
+
}
|
|
143
|
+
const end = performance.now();
|
|
144
|
+
fillMs = fillMs + (strokeStart - fillStart);
|
|
145
|
+
strokeMs = strokeMs + (textStart - strokeStart);
|
|
146
|
+
textMs = textMs + (imageStart - textStart);
|
|
147
|
+
imageMs = imageMs + (end - imageStart);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const start = win.stats();
|
|
151
|
+
let frame = 0;
|
|
152
|
+
let fillMs = 0;
|
|
153
|
+
let strokeMs = 0;
|
|
154
|
+
let textMs = 0;
|
|
155
|
+
let imageMs = 0;
|
|
156
|
+
|
|
157
|
+
const report = (): void => {
|
|
158
|
+
const end = win.stats();
|
|
159
|
+
const draws = end.canvasDraws - start.canvasDraws;
|
|
160
|
+
const uploads = end.canvasUploads - start.canvasUploads;
|
|
161
|
+
const bytes = end.canvasUploadBytes - start.canvasUploadBytes;
|
|
162
|
+
console.log("bench.canvas ms=" + round((fillMs + strokeMs + textMs + imageMs) / FRAMES) +
|
|
163
|
+
" fill=" + round(fillMs / FRAMES) +
|
|
164
|
+
" stroke=" + round(strokeMs / FRAMES) +
|
|
165
|
+
" text=" + round(textMs / FRAMES) +
|
|
166
|
+
" image=" + round(imageMs / FRAMES) +
|
|
167
|
+
" draws=" + draws +
|
|
168
|
+
" uploads=" + uploads +
|
|
169
|
+
" bytes=" + bytes +
|
|
170
|
+
" frames=" + FRAMES);
|
|
171
|
+
win.close();
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const tick = (): void => {
|
|
175
|
+
scene();
|
|
176
|
+
frame = frame + 1;
|
|
177
|
+
if (frame < FRAMES) {
|
|
178
|
+
win.requestAnimationFrame(tick);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
/* Report one frame later: the counters of the last scene are only
|
|
182
|
+
* folded into the totals when that frame ends. */
|
|
183
|
+
win.requestAnimationFrame(report);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
win.on("ready", () => win.requestAnimationFrame(tick));
|
|
187
|
+
win.on("close", () => console.log("bench.canvas closed"));
|
|
188
|
+
run();
|
|
189
|
+
`, { autocloseMs: 20000, console: true });
|
|
190
|
+
expect(result.stdout).toContain("bench.canvas closed");
|
|
191
|
+
const benches = parseBenches(result.stdout);
|
|
192
|
+
console.log("canvas draw perf: " + result.stdout.split("\n").find((line) => line.startsWith("bench.canvas")));
|
|
193
|
+
/* 5000 fillRects + 200 strokes + 300 fillTexts + 200 drawImages per frame. */
|
|
194
|
+
expect(field(benches, "canvas", "draws")).toBe(5700 * FRAMES);
|
|
195
|
+
/* Every drawn frame re-uploads the changed bitmap once — not K times for
|
|
196
|
+
* K canvases once the uploads share the frame's command buffer. */
|
|
197
|
+
expect(field(benches, "canvas", "uploads")).toBeGreaterThanOrEqual(FRAMES);
|
|
198
|
+
expect(field(benches, "canvas", "uploads")).toBeLessThanOrEqual(FRAMES + 2);
|
|
199
|
+
expect(field(benches, "canvas", "bytes")).toBeGreaterThan(0);
|
|
200
|
+
const budget = strictMs();
|
|
201
|
+
if (budget > 0)
|
|
202
|
+
expect(field(benches, "canvas", "ms")).toBeLessThan(budget);
|
|
203
|
+
}, 120000);
|
|
204
|
+
it("uploads only the dirty rectangle of a canvas", () => {
|
|
205
|
+
const result = harness.compileAndRun("drawbench-dirty", `
|
|
206
|
+
import { createWindow, run } from "gui";
|
|
207
|
+
|
|
208
|
+
const W = 640;
|
|
209
|
+
const H = 480;
|
|
210
|
+
const FRAMES = 8;
|
|
211
|
+
|
|
212
|
+
const HTML = "<html><head><style>body { margin: 0; }</style></head><body>" +
|
|
213
|
+
"<canvas id='c' width='" + W + "' height='" + H + "'></canvas></body></html>";
|
|
214
|
+
const win = createWindow({ title: "drawbench-dirty", width: 400, height: 400 });
|
|
215
|
+
win.loadHTML(HTML);
|
|
216
|
+
|
|
217
|
+
const canvas: any = win.document.getElementById("c");
|
|
218
|
+
const ctx: any = canvas.getContext("2d");
|
|
219
|
+
/* One full-canvas paint first: its upload is not part of the sample. */
|
|
220
|
+
ctx.fillStyle = "#123456";
|
|
221
|
+
ctx.fillRect(0, 0, W, H);
|
|
222
|
+
|
|
223
|
+
let frame = 0;
|
|
224
|
+
let start: any = null;
|
|
225
|
+
|
|
226
|
+
const report = (): void => {
|
|
227
|
+
const end = win.stats();
|
|
228
|
+
console.log("bench.dirty bytes=" + (end.canvasUploadBytes - start.canvasUploadBytes) +
|
|
229
|
+
" uploads=" + (end.canvasUploads - start.canvasUploads) +
|
|
230
|
+
" frames=" + (FRAMES - 1));
|
|
231
|
+
win.close();
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
const tick = (): void => {
|
|
235
|
+
if (frame === 1) start = win.stats();
|
|
236
|
+
ctx.fillStyle = "#ff0000";
|
|
237
|
+
ctx.fillRect(10, 10, 100, 100);
|
|
238
|
+
frame = frame + 1;
|
|
239
|
+
if (frame < FRAMES) {
|
|
240
|
+
win.requestAnimationFrame(tick);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
win.requestAnimationFrame(report);
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
win.on("ready", () => win.requestAnimationFrame(tick));
|
|
247
|
+
win.on("close", () => console.log("bench.dirty closed"));
|
|
248
|
+
run();
|
|
249
|
+
`, { autocloseMs: 10000, console: true });
|
|
250
|
+
expect(result.stdout).toContain("bench.dirty closed");
|
|
251
|
+
const benches = parseBenches(result.stdout);
|
|
252
|
+
console.log("canvas dirty upload: " +
|
|
253
|
+
result.stdout.split("\n").find((line) => line.startsWith("bench.dirty")));
|
|
254
|
+
const frames = 8 - 1;
|
|
255
|
+
expect(field(benches, "dirty", "uploads")).toBe(frames);
|
|
256
|
+
/* 100x100x4 bytes per frame, not the whole 640x480 bitmap. */
|
|
257
|
+
expect(field(benches, "dirty", "bytes")).toBeLessThanOrEqual(100 * 100 * 4 * frames + 4 * frames);
|
|
258
|
+
expect(field(benches, "dirty", "bytes")).toBeGreaterThan(0);
|
|
259
|
+
}, 120000);
|
|
260
|
+
it("issues many WebGL draws without restarting the pass or the pipeline", () => {
|
|
261
|
+
const result = harness.compileAndRun("drawbench-webgl", `
|
|
262
|
+
import { createWindow, run } from "gui";
|
|
263
|
+
|
|
264
|
+
const HTML = "<html><head><style>body { margin: 0; }</style></head><body>" +
|
|
265
|
+
"<canvas id='c' width='512' height='512'></canvas></body></html>";
|
|
266
|
+
|
|
267
|
+
const win = createWindow({ title: "drawbench-webgl", width: 700, height: 700 });
|
|
268
|
+
win.loadHTML(HTML);
|
|
269
|
+
|
|
270
|
+
const round = (value: number): number => Math.round(value * 100) / 100;
|
|
271
|
+
|
|
272
|
+
const start = (): void => {
|
|
273
|
+
const canvas: any = win.document.getElementById("c");
|
|
274
|
+
const gl: any = canvas.getContext("webgl");
|
|
275
|
+
if (gl == null) {
|
|
276
|
+
console.log("bench.webgl unsupported");
|
|
277
|
+
win.close();
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const vs: any = gl.createShader(gl.VERTEX_SHADER);
|
|
282
|
+
gl.shaderSource(vs, "attribute vec3 a_pos; uniform mat4 u_mvp;" +
|
|
283
|
+
"void main() { gl_Position = u_mvp * vec4(a_pos, 1.0); }");
|
|
284
|
+
gl.compileShader(vs);
|
|
285
|
+
const fs: any = gl.createShader(gl.FRAGMENT_SHADER);
|
|
286
|
+
gl.shaderSource(fs, "precision mediump float; uniform vec3 u_color;" +
|
|
287
|
+
"void main() { gl_FragColor = vec4(u_color, 1.0); }");
|
|
288
|
+
gl.compileShader(fs);
|
|
289
|
+
const program: any = gl.createProgram();
|
|
290
|
+
gl.attachShader(program, vs);
|
|
291
|
+
gl.attachShader(program, fs);
|
|
292
|
+
gl.linkProgram(program);
|
|
293
|
+
gl.useProgram(program);
|
|
294
|
+
|
|
295
|
+
const positions = new Float32Array([
|
|
296
|
+
-5, -5, -5, 5, -5, -5, 5, 5, -5, -5, 5, -5,
|
|
297
|
+
-5, -5, 5, 5, -5, 5, 5, 5, 5, -5, 5, 5,
|
|
298
|
+
]);
|
|
299
|
+
const indices = new Uint16Array([
|
|
300
|
+
0, 1, 2, 0, 2, 3, 4, 6, 5, 4, 7, 6,
|
|
301
|
+
0, 4, 5, 0, 5, 1, 3, 2, 6, 3, 6, 7,
|
|
302
|
+
1, 5, 6, 1, 6, 2, 0, 3, 7, 0, 7, 4,
|
|
303
|
+
]);
|
|
304
|
+
const vbo: any = gl.createBuffer();
|
|
305
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
306
|
+
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
|
|
307
|
+
const pos: any = gl.getAttribLocation(program, "a_pos");
|
|
308
|
+
gl.enableVertexAttribArray(pos);
|
|
309
|
+
gl.vertexAttribPointer(pos, 3, gl.FLOAT, false, 0, 0);
|
|
310
|
+
const ibo: any = gl.createBuffer();
|
|
311
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
312
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
|
|
313
|
+
const mvpLocation: any = gl.getUniformLocation(program, "u_mvp");
|
|
314
|
+
const colorLocation: any = gl.getUniformLocation(program, "u_color");
|
|
315
|
+
|
|
316
|
+
/* A 4 MiB dynamic buffer, patched with 64 KiB per frame. */
|
|
317
|
+
const big = new Float32Array(1024 * 1024);
|
|
318
|
+
const bigBuffer: any = gl.createBuffer();
|
|
319
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, bigBuffer);
|
|
320
|
+
gl.bufferData(gl.ARRAY_BUFFER, big, gl.DYNAMIC_DRAW);
|
|
321
|
+
const patch = new Float32Array(16384);
|
|
322
|
+
for (let i = 0; i < patch.length; i++) patch[i] = i % 7;
|
|
323
|
+
|
|
324
|
+
const matrix = new Float32Array(16);
|
|
325
|
+
matrix[0] = 0.05;
|
|
326
|
+
matrix[5] = 0.05;
|
|
327
|
+
matrix[10] = 0.05;
|
|
328
|
+
matrix[15] = 1.0;
|
|
329
|
+
|
|
330
|
+
const scene = (): void => {
|
|
331
|
+
gl.clearColor(0, 0, 0, 1);
|
|
332
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
333
|
+
for (let i = 0; i < 2000; i++) {
|
|
334
|
+
matrix[12] = ((i % 40) - 20) * 0.045;
|
|
335
|
+
matrix[13] = (Math.floor(i / 40) - 20) * 0.045;
|
|
336
|
+
gl.uniformMatrix4fv(mvpLocation, false, matrix);
|
|
337
|
+
gl.uniform3f(colorLocation, 1.0, 0.5, 0.2);
|
|
338
|
+
gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
|
|
339
|
+
}
|
|
340
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, bigBuffer);
|
|
341
|
+
gl.bufferSubData(gl.ARRAY_BUFFER, 0, patch);
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
let frame = 0;
|
|
345
|
+
let drawMs = 0;
|
|
346
|
+
let start: any = null;
|
|
347
|
+
|
|
348
|
+
const report = (): void => {
|
|
349
|
+
const end = win.stats();
|
|
350
|
+
const frames = ${FRAMES} - 1;
|
|
351
|
+
console.log("bench.webgl ms=" + round(drawMs / ${FRAMES}) +
|
|
352
|
+
" draws=" + (end.webglDraws - start.webglDraws) +
|
|
353
|
+
" passes=" + (end.webglPasses - start.webglPasses) +
|
|
354
|
+
" misses=" + (end.webglPipelineMisses - start.webglPipelineMisses) +
|
|
355
|
+
" bytes=" + (end.webglBufferUploadBytes - start.webglBufferUploadBytes) +
|
|
356
|
+
" frames=" + frames);
|
|
357
|
+
win.close();
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const tick = (): void => {
|
|
361
|
+
/* The first frame creates the pipeline and uploads the two buffers;
|
|
362
|
+
* sampling after it keeps those one-time costs out of the counters. */
|
|
363
|
+
if (frame === 1) start = win.stats();
|
|
364
|
+
const t0 = performance.now();
|
|
365
|
+
scene();
|
|
366
|
+
drawMs = drawMs + (performance.now() - t0);
|
|
367
|
+
frame = frame + 1;
|
|
368
|
+
if (frame < ${FRAMES}) {
|
|
369
|
+
win.requestAnimationFrame(tick);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
/* Report one frame later, so the last scene's counters have been
|
|
373
|
+
* folded into the frame totals. */
|
|
374
|
+
win.requestAnimationFrame(report);
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
win.requestAnimationFrame(tick);
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
win.on("ready", start);
|
|
381
|
+
win.on("close", () => console.log("bench.webgl closed"));
|
|
382
|
+
run();
|
|
383
|
+
`, { autocloseMs: 30000, console: true });
|
|
384
|
+
expect(result.stdout).toContain("bench.webgl closed");
|
|
385
|
+
if (result.stdout.includes("bench.webgl unsupported")) {
|
|
386
|
+
console.log("webgl draw perf: unsupported on this backend");
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const benches = parseBenches(result.stdout);
|
|
390
|
+
console.log("webgl draw perf: " + result.stdout.split("\n").find((line) => line.startsWith("bench.webgl")));
|
|
391
|
+
const frames = FRAMES - 1;
|
|
392
|
+
expect(field(benches, "webgl", "draws")).toBe(2000 * frames);
|
|
393
|
+
/* Warm-up created the pipeline; steady state must not create more. */
|
|
394
|
+
expect(field(benches, "webgl", "misses")).toBe(0);
|
|
395
|
+
/* One clear + one draw pass per frame, not one pass per draw call. */
|
|
396
|
+
expect(field(benches, "webgl", "passes")).toBeGreaterThan(0);
|
|
397
|
+
expect(field(benches, "webgl", "passes")).toBeLessThanOrEqual(2 * frames);
|
|
398
|
+
/* Only the patched range is re-uploaded, not the whole 4 MiB buffer. */
|
|
399
|
+
expect(field(benches, "webgl", "bytes")).toBeLessThanOrEqual(65536 * frames + 4 * frames);
|
|
400
|
+
const budget = strictMs();
|
|
401
|
+
if (budget > 0)
|
|
402
|
+
expect(field(benches, "webgl", "ms")).toBeLessThan(budget);
|
|
403
|
+
}, 120000);
|
|
404
|
+
});
|
|
405
|
+
//# sourceMappingURL=gui-draw-perf.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gui-draw-perf.test.js","sourceRoot":"","sources":["../../../tests/e2e/gui-draw-perf.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end test for the `gui` extension — rendering performance counters.
|
|
3
|
+
*
|
|
4
|
+
* A 200-row list (about 1,000 boxes plus text) is loaded, then one thing is
|
|
5
|
+
* changed per frame: a text node, a class, an inline width, and a burst of
|
|
6
|
+
* pointer moves. The engine reports what each frame actually did through
|
|
7
|
+
* `win.stats()` (see `runtime/ext_gui/perf.h`), and the test pins the shape of
|
|
8
|
+
* that work:
|
|
9
|
+
*
|
|
10
|
+
* - a text/class/width change restyles once and repaints once;
|
|
11
|
+
* - a pointer move over a page without `:hover` rules does not restyle;
|
|
12
|
+
* - an idle frame lays out, paints, uploads and presents nothing (a present
|
|
13
|
+
* the window system asked for, or one a starved frame had to defer, is
|
|
14
|
+
* reported separately as `exposes`/`deferred` and is not counted as the
|
|
15
|
+
* page's work);
|
|
16
|
+
* - `@media` is evaluated once per rule, not once per rule and node;
|
|
17
|
+
* - unchanged text is shaped once and then served from the cache.
|
|
18
|
+
*
|
|
19
|
+
* Only counters are asserted (they are deterministic); the wall-clock numbers
|
|
20
|
+
* are printed for a human and, on the machine that ran the suite, compared
|
|
21
|
+
* against `XBINTSC_GUI_PERF_STRICT_MS` (unset in CI, where the GPU is software).
|
|
22
|
+
*/
|
|
23
|
+
export {};
|