1/**
2 * The one entry point: compile a MATLAB script and run it on a GPUDevice.
3 *
4 * Compilation (numbl lowering + WGSL pipeline builds) is timed separately
5 * from execution — the execution numbers are the ones to compare with MATLAB.
6 */
7import { compileScript } from './compile.ts';
8import { planScript, type KernelSource, type ScriptPlan } from './plan.ts';
9import { executePlan, type RunResult } from './run.ts';
10import { asCompileError } from './errors.ts';
12export interface ScriptRun {
13 compileSeconds: number;
14 /** Human-readable op sequence, for the "what did this compile to" pane. */
15 planDescription: string[];
16 /** The WGSL of every distinct kernel the script compiled to. */
17 kernels: KernelSource[];
18 result: RunResult;
19}
21export interface SandboxGpu {
22 device: GPUDevice;
23 /** Human-readable adapter description, for the "ran on" line. */
24 description: string;
25}
27export async function requestSandboxDevice(): Promise<SandboxGpu> {
28 if (!navigator.gpu) {
29 throw new Error('WebGPU is not available in this browser');
30 }
31 const adapter = await navigator.gpu.requestAdapter();
32 if (!adapter) throw new Error('No WebGPU adapter available');
33 const want = (name: keyof GPUSupportedLimits): Record<string, number> => ({
34 [name]: adapter.limits[name] as number,
35 });
36 const device = await adapter.requestDevice({
37 requiredLimits: {
38 ...want('maxStorageBufferBindingSize'),
39 ...want('maxBufferSize'),
40 ...want('maxStorageBuffersPerShaderStage'),
41 },
42 });
43 const info = adapter.info;
44 const description =
45 [info?.description || info?.architecture, info?.vendor]
46 .filter(Boolean)
47 .join(' — ') || 'unknown adapter';
48 return { device, description };
49}
51export async function runScript(
52 device: GPUDevice,
53 source: string,
54 onOutput?: (text: string) => void,
55): Promise<ScriptRun> {
56 const t0 = performance.now();
57 let plan: ScriptPlan;
58 try {
59 const compiled = compileScript(source);
60 plan = await planScript(device, compiled);
61 } catch (e) {
62 throw asCompileError(e);
63 }
64 const compileSeconds = (performance.now() - t0) / 1000;
65 try {
66 const result = await executePlan(device, plan, onOutput);
67 return {
68 compileSeconds,
69 planDescription: plan.describe(),
70 kernels: plan.kernels,
71 result,
72 };
73 } finally {
74 plan.destroy();
75 }
76}