gpu-atlas 0.1.0
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/LICENSE +21 -0
- package/README.md +248 -0
- package/dist/gpu-atlas.js +1938 -0
- package/dist/gpu-atlas.js.map +1 -0
- package/dist/index.d.ts +398 -0
- package/package.json +59 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gpu-atlas.js","sources":["../src/types.ts","../src/probe/adapter.ts","../src/probe/format-table.ts","../src/probe/errors.ts","../src/probe/formats.ts","../src/probe/shaders.ts","../src/probe/limits.ts","../src/probe/timer.ts","../src/probe/quantization.ts","../src/probe/bench.ts","../src/probe/discrepancies.ts","../src/probe/fingerprint.ts","../src/probe/index.ts","../src/compare.ts","../src/index.ts"],"sourcesContent":["// gpu-atlas profile schema.\r\n//\r\n// The premise of this library: what adapter.limits / adapter.features claim and\r\n// what the device actually does are different things. So every capability is\r\n// recorded along two tracks:\r\n// declared — what the browser reported about itself\r\n// verified — what actually worked when we created it, drew with it, measured it\r\n// Where the two disagree is a Discrepancy, and that is the data this project\r\n// exists to collect.\r\n\r\n/**\r\n * Profile schema version.\r\n *\r\n * Collecting profiles is the point of this project, so a profile has to say\r\n * honestly what shape it is. Bump this whenever a field is added, removed, or\r\n * changes meaning, and record why below — consumers compare against it to know\r\n * which fields they can rely on.\r\n *\r\n * 4 — EnvironmentInfo.userAgent removed.\r\n * Browser, version, platform and mobile are already parsed into their own\r\n * fields, so the raw string was duplicate data — and a fingerprinting\r\n * vector. A project that asks people to share profiles should not ship\r\n * identifying information it does not use.\r\n *\r\n * 3 — Errors became structured, and fingerprints got wider.\r\n * Wall-clock benchmarks also changed: they now scale to 60 ticks of the\r\n * measured performance.now() granularity and drop their extreme samples,\r\n * so those figures shift by a few percent against version 2. GPU-timed\r\n * benchmarks are unaffected, which is why version 2 profiles remain\r\n * comparable rather than being cut off.\r\n * ~ FormatSupport.errors and LimitProbe.error are now ProbeError objects\r\n * rather than preformatted strings, so a consumer can branch on why\r\n * something failed without matching on message text.\r\n * ~ AtlasProfile.fingerprint is a 32-character hash instead of 8. The old\r\n * 32-bit value collided at a rate that mattered once profiles were being\r\n * collected in bulk.\r\n *\r\n * 2 — Measurement trustworthiness became explicit.\r\n * + BenchResult.repetitions how far auto-scaling pushed each benchmark\r\n * + BenchResult.ticks duration in timer-resolution units\r\n * + BenchResult.quantized sitting on the quantization floor\r\n * + BenchmarkResults.timerResolutionNs measured GPU timer granularity\r\n * + BenchmarkResults.wallClockResolutionMs measured performance.now() granularity\r\n * + ShaderCase.skipped previously inferred from message text\r\n * Benchmarks also changed: the overdraw ones now blend additively, so their\r\n * numbers are not comparable with version 1 readings taken on tile-based\r\n * deferred GPUs, where the unblended version measured almost nothing.\r\n *\r\n * 1 — Initial schema.\r\n */\r\nexport const SCHEMA_VERSION = 4;\r\n\r\n/**\r\n * Below this, benchmark numbers cannot be trusted for comparison: version 1\r\n * profiles carry no quantization information, and their overdraw benchmarks\r\n * were architecture-dependent.\r\n */\r\nexport const MIN_COMPARABLE_BENCHMARK_SCHEMA = 2;\r\n\r\n// ── Environment ─────────────────────────────────────────\r\n\r\nexport interface EnvironmentInfo {\r\n /** From UA-CH when available */\r\n platform?: string;\r\n /** 'Chrome' | 'Firefox' | 'Safari' | 'Edge' | 'unknown' */\r\n browser: string;\r\n browserVersion: string;\r\n /** Prefers the UA-CH mobile hint, falls back to UA sniffing */\r\n mobile: boolean;\r\n deviceMemoryGB?: number;\r\n hardwareConcurrency?: number;\r\n devicePixelRatio: number;\r\n}\r\n\r\n// ── Adapter ─────────────────────────────────────────────\r\n\r\nexport interface AdapterIdentity {\r\n vendor: string;\r\n architecture: string;\r\n device: string;\r\n description: string;\r\n /** A software adapter — every performance number means something else entirely */\r\n isFallbackAdapter: boolean;\r\n /** The powerPreference passed to requestAdapter */\r\n powerPreference: GPUPowerPreference | 'default';\r\n}\r\n\r\n// ── Declared capabilities ───────────────────────────────\r\n\r\nexport interface DeclaredCapabilities {\r\n features: string[];\r\n limits: Record<string, number>;\r\n /** navigator.gpu.getPreferredCanvasFormat() */\r\n preferredCanvasFormat: string;\r\n}\r\n\r\n// ── Errors ──────────────────────────────────────────────\r\n\r\n/**\r\n * Why something failed. `validation` and `out-of-memory` come straight from\r\n * WebGPU error scopes; `exception` means the call threw synchronously, which is\r\n * what browsers do for a format they do not recognise at all.\r\n */\r\nexport type ProbeErrorKind =\r\n | 'validation'\r\n | 'out-of-memory'\r\n | 'internal'\r\n | 'exception'\r\n | 'queue'\r\n | 'scope-unavailable';\r\n\r\n/** Which check was running when an error surfaced */\r\nexport type ProbeStage =\r\n | 'create'\r\n | 'sample'\r\n | 'render'\r\n | 'blend'\r\n | 'storage'\r\n | 'msaa4x'\r\n | 'limit';\r\n\r\nexport interface ProbeError {\r\n kind: ProbeErrorKind;\r\n message: string;\r\n stage?: ProbeStage;\r\n}\r\n\r\n// ── Verified capabilities ───────────────────────────────\r\n\r\n/** Whether a texture format actually works for each usage */\r\nexport interface FormatSupport {\r\n format: string;\r\n /** The device feature this format requires, if any */\r\n requiresFeature?: string;\r\n /** Whether that feature appears in declared.features */\r\n featureDeclared: boolean;\r\n /** createTexture succeeds */\r\n creatable: boolean;\r\n /** Readable from a shader via TEXTURE_BINDING */\r\n sampleable: boolean;\r\n /** A render pass actually runs against it via RENDER_ATTACHMENT */\r\n renderable: boolean;\r\n /** Blending works when used as a render target */\r\n blendable: boolean;\r\n /** Writable from a compute shader via STORAGE_BINDING */\r\n storageWritable: boolean;\r\n /** Works as a 4x MSAA render target */\r\n multisample4x: boolean;\r\n /** Errors captured at each stage, for diagnosis */\r\n errors: ProbeError[];\r\n}\r\n\r\n/** Result of one WGSL compilation case */\r\nexport interface ShaderCase {\r\n id: string;\r\n /** What this case is probing for */\r\n description: string;\r\n /** Skipped because a required feature is missing */\r\n skipped: boolean;\r\n compiled: boolean;\r\n /** Compiling can succeed while pipeline creation still fails — it happens */\r\n pipelineCreated: boolean;\r\n /** Warnings and errors from getCompilationInfo() */\r\n messages: ShaderMessage[];\r\n /** Compile time in ms. Identifies devices with slow shader compilation */\r\n compileMs: number;\r\n}\r\n\r\nexport interface ShaderMessage {\r\n type: 'error' | 'warning' | 'info';\r\n message: string;\r\n lineNum: number;\r\n}\r\n\r\n/** Whether a declared limit can actually be used up to its stated value */\r\nexport interface LimitProbe {\r\n limit: string;\r\n declared: number;\r\n /** Highest value that actually allocated, found by bisection */\r\n achieved: number;\r\n /** achieved < declared means the declaration was not honored */\r\n honored: boolean;\r\n error?: ProbeError;\r\n}\r\n\r\nexport interface VerifiedCapabilities {\r\n formats: FormatSupport[];\r\n shaders: ShaderCase[];\r\n limits: LimitProbe[];\r\n /** The device died partway through — everything after that is meaningless */\r\n deviceLost: boolean;\r\n deviceLostReason?: string;\r\n}\r\n\r\n// ── Benchmarks ──────────────────────────────────────────\r\n\r\nexport interface BenchResult {\r\n id: string;\r\n description: string;\r\n /** Representative value (median), in ms */\r\n medianMs: number;\r\n /** Lowest sample — a noise-free floor */\r\n minMs: number;\r\n /** Coefficient of variation. High means this number should not be trusted */\r\n variation: number;\r\n /** Throughput in the unit this benchmark defines (draws/s, MPixel/s, ...) */\r\n throughput?: number;\r\n throughputUnit?: string;\r\n /** Whether this came from GPU timestamps or the wall clock */\r\n timing: 'timestamp-query' | 'wall-clock';\r\n samples: number;\r\n /** How many unit workloads were run per sample after auto-scaling */\r\n repetitions: number;\r\n /**\r\n * Measured duration expressed in timer resolution units. Low values mean the\r\n * number is riding on the quantization floor and carries little information,\r\n * which is the one case where a variation of 0 must not be read as stability.\r\n */\r\n ticks?: number;\r\n /** The measurement sits too close to the timer resolution to be trusted */\r\n quantized?: boolean;\r\n failed?: string;\r\n}\r\n\r\nexport interface BenchmarkResults {\r\n results: BenchResult[];\r\n /** Whether timestamp-query was usable */\r\n timestampQuery: boolean;\r\n /**\r\n * Measured granularity of the GPU timer, in nanoseconds. Browsers round\r\n * timestamps into coarse buckets as a Spectre mitigation and the bucket size\r\n * differs per browser and device, so it is measured rather than assumed.\r\n */\r\n timerResolutionNs: number | null;\r\n /**\r\n * Measured granularity of performance.now(), in milliseconds. Safari rounds\r\n * to 1ms, which bounds how precisely the wall-clock benchmarks can be read.\r\n */\r\n wallClockResolutionMs: number | null;\r\n /** Wall-clock time the whole benchmark suite took */\r\n totalMs: number;\r\n}\r\n\r\n// ── Discrepancies ───────────────────────────────────────\r\n\r\nexport type DiscrepancyKind =\r\n | 'format-declared-not-usable' // feature is declared but the format does not work\r\n | 'format-usable-not-declared' // not declared, yet it works anyway\r\n | 'limit-not-honored' // the declared limit cannot actually be reached\r\n | 'shader-compile-failure' // valid WGSL that failed to compile\r\n | 'shader-pipeline-failure' // compiled, but pipeline creation failed\r\n | 'performance-cliff'; // same work, anomalously slow or unstable\r\n\r\nexport interface Discrepancy {\r\n kind: DiscrepancyKind;\r\n /** Where it occurred — a format name, limit name, or shader case id */\r\n subject: string;\r\n detail: string;\r\n /** 'breaking' means code relying on the declaration will fail on this device */\r\n severity: 'breaking' | 'degraded' | 'note';\r\n}\r\n\r\n// ── The profile ─────────────────────────────────────────\r\n\r\nexport interface AtlasProfile {\r\n schema: number;\r\n capturedAt: string;\r\n /**\r\n * Stable hash grouping the same device + browser combination. 32 hex\r\n * characters — wide enough that collisions stay negligible across a large\r\n * collection of profiles, which an 8-character hash was not.\r\n */\r\n fingerprint: string;\r\n environment: EnvironmentInfo;\r\n adapter: AdapterIdentity | null;\r\n declared: DeclaredCapabilities | null;\r\n verified: VerifiedCapabilities | null;\r\n benchmarks: BenchmarkResults | null;\r\n discrepancies: Discrepancy[];\r\n /** Why WebGPU could not be used at all, when that is the case */\r\n unavailable?: string;\r\n /** Total time the probe took */\r\n elapsedMs: number;\r\n}\r\n\r\n// ── Probe options ───────────────────────────────────────\r\n\r\nexport interface ProbeOptions {\r\n /** Which GPU to ask for. On laptops this decides which chip you get */\r\n powerPreference?: GPUPowerPreference;\r\n /** Run benchmarks. false leaves only capability verification, which is fast */\r\n benchmark?: boolean;\r\n /** Samples per benchmark. More is more accurate and slower. Clamped to 1-99 */\r\n benchSamples?: number;\r\n /** Progress callback */\r\n onProgress?: (stage: string, ratio: number) => void;\r\n /** Verify only these texture formats (default: the full built-in list) */\r\n formats?: string[];\r\n}\r\n","// Acquiring the adapter and device, plus environment collection.\r\n\r\nimport type {\r\n AdapterIdentity,\r\n DeclaredCapabilities,\r\n EnvironmentInfo,\r\n} from '../types.js';\r\n\r\nexport interface Acquired {\r\n adapter: GPUAdapter;\r\n device: GPUDevice;\r\n identity: AdapterIdentity;\r\n declared: DeclaredCapabilities;\r\n /** Features and limits that were requested but refused */\r\n denied: string[];\r\n lost: Promise<GPUDeviceLostInfo>;\r\n}\r\n\r\nexport class WebGPUUnavailable extends Error {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = 'WebGPUUnavailable';\r\n }\r\n}\r\n\r\nexport async function acquire(\r\n powerPreference?: GPUPowerPreference,\r\n): Promise<Acquired> {\r\n if (typeof navigator === 'undefined' || !navigator.gpu) {\r\n throw new WebGPUUnavailable('navigator.gpu is missing — this browser has no WebGPU');\r\n }\r\n\r\n const adapter = await navigator.gpu.requestAdapter(\r\n powerPreference ? { powerPreference } : undefined,\r\n );\r\n if (!adapter) {\r\n throw new WebGPUUnavailable(\r\n 'requestAdapter returned null — the WebGPU API exists but no usable adapter does',\r\n );\r\n }\r\n\r\n const identity = await readIdentity(adapter, powerPreference);\r\n\r\n // Ask for every declared feature and limit. Being refused here is itself data.\r\n const features = [...adapter.features] as GPUFeatureName[];\r\n const limits = limitsToRecord(adapter.limits);\r\n\r\n const denied: string[] = [];\r\n let device = await tryDevice(adapter, features, limits);\r\n\r\n if (!device) {\r\n // Some implementations refuse the full limits block. Try features alone.\r\n denied.push('requiredLimits (all)');\r\n device = await tryDevice(adapter, features, undefined);\r\n }\r\n if (!device) {\r\n // Features are a problem too — find a subset that survives by adding them\r\n // one at a time. This is greedy and order-dependent: a feature that works\r\n // alone but conflicts with an earlier one is recorded as denied even though\r\n // a different ordering would have kept it. Testing every combination is\r\n // exponential, and no implementation has been observed to need it.\r\n denied.push('requiredFeatures (all)');\r\n const survivors: GPUFeatureName[] = [];\r\n for (const f of features) {\r\n const d = await tryDevice(adapter, [...survivors, f], undefined);\r\n if (d) {\r\n survivors.push(f);\r\n d.destroy();\r\n } else {\r\n denied.push(`feature:${f}`);\r\n }\r\n }\r\n device = await tryDevice(adapter, survivors, undefined);\r\n }\r\n if (!device) {\r\n throw new WebGPUUnavailable(\r\n 'requestDevice kept failing — there is an adapter but no device can be created from it',\r\n );\r\n }\r\n\r\n const declared: DeclaredCapabilities = {\r\n features: [...adapter.features].sort(),\r\n limits,\r\n preferredCanvasFormat: safePreferredFormat(),\r\n };\r\n\r\n return { adapter, device, identity, declared, denied, lost: device.lost };\r\n}\r\n\r\nasync function tryDevice(\r\n adapter: GPUAdapter,\r\n features: GPUFeatureName[],\r\n limits: Record<string, number> | undefined,\r\n): Promise<GPUDevice | null> {\r\n try {\r\n const desc: GPUDeviceDescriptor = { requiredFeatures: features };\r\n if (limits) desc.requiredLimits = limits;\r\n return await adapter.requestDevice(desc);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nasync function readIdentity(\r\n adapter: GPUAdapter,\r\n powerPreference?: GPUPowerPreference,\r\n): Promise<AdapterIdentity> {\r\n // Current spec exposes a sync property; older builds had requestAdapterInfo().\r\n let info: GPUAdapterInfo | undefined = (adapter as { info?: GPUAdapterInfo }).info;\r\n if (!info) {\r\n const legacy = adapter as unknown as { requestAdapterInfo?: () => Promise<GPUAdapterInfo> };\r\n if (typeof legacy.requestAdapterInfo === 'function') {\r\n try {\r\n info = await legacy.requestAdapterInfo();\r\n } catch {\r\n info = undefined;\r\n }\r\n }\r\n }\r\n\r\n return {\r\n vendor: info?.vendor ?? '',\r\n architecture: info?.architecture ?? '',\r\n device: info?.device ?? '',\r\n description: info?.description ?? '',\r\n // isFallbackAdapter has lived on both the adapter and its info over time.\r\n isFallbackAdapter:\r\n (adapter as { isFallbackAdapter?: boolean }).isFallbackAdapter ??\r\n (info as { isFallbackAdapter?: boolean } | undefined)?.isFallbackAdapter ??\r\n false,\r\n powerPreference: powerPreference ?? 'default',\r\n };\r\n}\r\n\r\nfunction limitsToRecord(limits: GPUSupportedLimits): Record<string, number> {\r\n const out: Record<string, number> = {};\r\n // GPUSupportedLimits is not a plain object — the values are prototype getters.\r\n for (const key of supportedLimitKeys(limits)) {\r\n const v = (limits as unknown as Record<string, unknown>)[key];\r\n if (typeof v === 'number' && Number.isFinite(v)) out[key] = v;\r\n }\r\n return out;\r\n}\r\n\r\nfunction supportedLimitKeys(limits: GPUSupportedLimits): string[] {\r\n const keys = new Set<string>();\r\n let proto: object | null = Object.getPrototypeOf(limits);\r\n while (proto && proto !== Object.prototype) {\r\n for (const k of Object.getOwnPropertyNames(proto)) {\r\n if (k !== 'constructor') keys.add(k);\r\n }\r\n proto = Object.getPrototypeOf(proto);\r\n }\r\n for (const k of Object.keys(limits)) keys.add(k);\r\n return [...keys].sort();\r\n}\r\n\r\nfunction safePreferredFormat(): string {\r\n try {\r\n return navigator.gpu.getPreferredCanvasFormat();\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\n// ── Environment ─────────────────────────────────────────\r\n\r\nexport async function readEnvironment(): Promise<EnvironmentInfo> {\r\n const ua = typeof navigator !== 'undefined' ? navigator.userAgent : '';\r\n const uaData = (navigator as { userAgentData?: NavigatorUAData }).userAgentData;\r\n\r\n let platform: string | undefined;\r\n let mobile: boolean | undefined;\r\n let brand: string | undefined;\r\n let brandVersion: string | undefined;\r\n\r\n if (uaData) {\r\n mobile = uaData.mobile;\r\n platform = uaData.platform;\r\n try {\r\n const high = await uaData.getHighEntropyValues(['platformVersion', 'fullVersionList']);\r\n const list = high.fullVersionList ?? uaData.brands;\r\n const primary = list?.find((b) => !/Not.?A.?Brand/i.test(b.brand));\r\n if (primary) {\r\n brand = primary.brand;\r\n brandVersion = primary.version;\r\n }\r\n if (high.platformVersion) platform = `${platform} ${high.platformVersion}`;\r\n } catch {\r\n // Permission or implementation gaps just fall through to UA parsing.\r\n }\r\n }\r\n\r\n const parsed = parseUA(ua);\r\n\r\n return {\r\n // The UA string is parsed above but deliberately not kept: everything the\r\n // profile needs from it is already broken out, and the raw value only adds\r\n // identifying detail to something people are asked to share.\r\n platform,\r\n browser: brand ?? parsed.browser,\r\n browserVersion: brandVersion ?? parsed.version,\r\n mobile: mobile ?? /Mobi|Android|iPhone|iPad/i.test(ua),\r\n deviceMemoryGB: (navigator as { deviceMemory?: number }).deviceMemory,\r\n hardwareConcurrency: navigator.hardwareConcurrency,\r\n devicePixelRatio: typeof devicePixelRatio === 'number' ? devicePixelRatio : 1,\r\n };\r\n}\r\n\r\nfunction parseUA(ua: string): { browser: string; version: string } {\r\n // Order matters — Edge's UA contains Chrome, and Chrome's contains Safari.\r\n const patterns: Array<[string, RegExp]> = [\r\n ['Edge', /Edg(?:e|A|iOS)?\\/([\\d.]+)/],\r\n ['Opera', /OPR\\/([\\d.]+)/],\r\n ['Firefox', /Firefox\\/([\\d.]+)/],\r\n ['Chrome', /(?:Chrome|CriOS)\\/([\\d.]+)/],\r\n ['Safari', /Version\\/([\\d.]+).*Safari/],\r\n ];\r\n for (const [name, re] of patterns) {\r\n const m = ua.match(re);\r\n if (m) return { browser: name, version: m[1] };\r\n }\r\n return { browser: 'unknown', version: '' };\r\n}\r\n\r\n// UA-CH types (not yet in lib.dom)\r\ninterface NavigatorUAData {\r\n brands: Array<{ brand: string; version: string }>;\r\n mobile: boolean;\r\n platform: string;\r\n getHighEntropyValues(hints: string[]): Promise<{\r\n platformVersion?: string;\r\n fullVersionList?: Array<{ brand: string; version: string }>;\r\n }>;\r\n}\r\n","// Texture format metadata.\n//\n// `expect` is what the WebGPU spec says should be true. It is not a value we\n// trust — it is the baseline we compare measurements against to find where an\n// implementation diverges.\n\nexport type FormatKind = 'color' | 'depth' | 'compressed';\n\nexport interface FormatMeta {\n format: string;\n kind: FormatKind;\n /** Texel type of the WGSL texture */\n texel: 'f32' | 'u32' | 'i32';\n /** Whether a filtering sampler may be attached (decides bindGroupLayout sampleType) */\n filterable: boolean;\n /** The device feature this format requires */\n requiresFeature?: string;\n /** Block size for compressed formats — createTexture must be a multiple of it */\n block?: [number, number];\n hasDepth?: boolean;\n hasStencil?: boolean;\n /** What the spec says to expect */\n expect: {\n renderable: boolean;\n blendable: boolean;\n storage: boolean;\n };\n}\n\nconst color = (\n format: string,\n texel: 'f32' | 'u32' | 'i32',\n filterable: boolean,\n expect: { renderable: boolean; blendable: boolean; storage: boolean },\n requiresFeature?: string,\n): FormatMeta => ({ format, kind: 'color', texel, filterable, expect, requiresFeature });\n\nconst NO = { renderable: false, blendable: false, storage: false };\nconst R_B = { renderable: true, blendable: true, storage: false };\nconst R__ = { renderable: true, blendable: false, storage: false };\nconst R_BS = { renderable: true, blendable: true, storage: true };\nconst R__S = { renderable: true, blendable: false, storage: true };\nconst ___S = { renderable: false, blendable: false, storage: true };\n\nexport const FORMATS: FormatMeta[] = [\n // ── 8-bit ──\n color('r8unorm', 'f32', true, R_B),\n color('r8snorm', 'f32', true, NO),\n color('r8uint', 'u32', false, R__),\n color('r8sint', 'i32', false, R__),\n\n // ── 16-bit ──\n color('r16uint', 'u32', false, R__),\n color('r16sint', 'i32', false, R__),\n color('r16float', 'f32', true, R_B),\n color('rg8unorm', 'f32', true, R_B),\n color('rg8snorm', 'f32', true, NO),\n color('rg8uint', 'u32', false, R__),\n color('rg8sint', 'i32', false, R__),\n\n // ── 32-bit ──\n color('r32uint', 'u32', false, R__S),\n color('r32sint', 'i32', false, R__S),\n // r32float renders but does not blend without float32-blendable\n color('r32float', 'f32', false, R__S),\n color('rg16uint', 'u32', false, R__),\n color('rg16sint', 'i32', false, R__),\n color('rg16float', 'f32', true, R_B),\n color('rgba8unorm', 'f32', true, R_BS),\n color('rgba8unorm-srgb', 'f32', true, R_B),\n color('rgba8snorm', 'f32', true, ___S),\n color('rgba8uint', 'u32', false, R__S),\n color('rgba8sint', 'i32', false, R__S),\n color('bgra8unorm', 'f32', true, R_B),\n color('bgra8unorm-srgb', 'f32', true, R_B),\n color('rgb10a2uint', 'u32', false, R__),\n color('rgb10a2unorm', 'f32', true, R_B),\n // rg11b10ufloat rendering sits behind its own feature gate\n color('rg11b10ufloat', 'f32', true, NO),\n\n // ── 64-bit ──\n color('rg32uint', 'u32', false, R__S),\n color('rg32sint', 'i32', false, R__S),\n color('rg32float', 'f32', false, R__S),\n color('rgba16uint', 'u32', false, R__S),\n color('rgba16sint', 'i32', false, R__S),\n color('rgba16float', 'f32', true, R_BS),\n\n // ── 128-bit ──\n color('rgba32uint', 'u32', false, R__S),\n color('rgba32sint', 'i32', false, R__S),\n color('rgba32float', 'f32', false, R__S),\n\n // ── Depth / stencil ──\n {\n format: 'stencil8', kind: 'depth', texel: 'u32', filterable: false,\n hasStencil: true, expect: R__,\n },\n {\n format: 'depth16unorm', kind: 'depth', texel: 'f32', filterable: false,\n hasDepth: true, expect: R__,\n },\n {\n format: 'depth24plus', kind: 'depth', texel: 'f32', filterable: false,\n hasDepth: true, expect: R__,\n },\n {\n format: 'depth24plus-stencil8', kind: 'depth', texel: 'f32', filterable: false,\n hasDepth: true, hasStencil: true, expect: R__,\n },\n {\n format: 'depth32float', kind: 'depth', texel: 'f32', filterable: false,\n hasDepth: true, expect: R__,\n },\n {\n format: 'depth32float-stencil8', kind: 'depth', texel: 'f32', filterable: false,\n hasDepth: true, hasStencil: true, requiresFeature: 'depth32float-stencil8',\n expect: R__,\n },\n\n // ── Compressed: BC (desktop) ──\n ...compressed(['bc1-rgba-unorm', 'bc3-rgba-unorm', 'bc4-r-unorm', 'bc5-rg-unorm',\n 'bc6h-rgb-ufloat', 'bc7-rgba-unorm'], 'texture-compression-bc', [4, 4]),\n\n // ── Compressed: ETC2 (mobile) ──\n ...compressed(['etc2-rgb8unorm', 'etc2-rgba8unorm', 'eac-r11unorm'],\n 'texture-compression-etc2', [4, 4]),\n\n // ── Compressed: ASTC (mobile) ──\n ...compressed(['astc-4x4-unorm'], 'texture-compression-astc', [4, 4]),\n ...compressed(['astc-8x8-unorm'], 'texture-compression-astc', [8, 8]),\n];\n\nfunction compressed(\n formats: string[],\n feature: string,\n block: [number, number],\n): FormatMeta[] {\n return formats.map((format) => ({\n format,\n kind: 'compressed' as const,\n texel: 'f32' as const,\n filterable: true,\n requiresFeature: feature,\n block,\n expect: NO,\n }));\n}\n\nexport function findMeta(format: string): FormatMeta | undefined {\n return FORMATS.find((f) => f.format === format);\n}\n\n// ── Feature-adjusted expectations ───────────────────────\n//\n// WebGPU widens format capabilities through features. The `expect` values above\n// are core-spec baselines, so using them unadjusted on a device with features\n// enabled produces a flood of false \"more permissive than spec\" reports. Raise\n// the baseline by whatever the device declares, then compare — what is left is\n// real divergence.\n\n/** Formats that texture-formats-tier1 grants storage binding to */\nconst TIER1_STORAGE = new Set([\n 'r8unorm', 'r8snorm', 'r8uint', 'r8sint',\n 'rg8unorm', 'rg8snorm', 'rg8uint', 'rg8sint',\n 'r16uint', 'r16sint', 'r16float',\n 'rg16uint', 'rg16sint', 'rg16float',\n 'rgb10a2unorm', 'rgb10a2uint', 'rg11b10ufloat',\n]);\n\n/** 32-bit float color formats — float32-blendable grants them blending */\nconst FLOAT32_COLOR = new Set(['r32float', 'rg32float', 'rgba32float']);\n\nexport function expectationsFor(\n meta: FormatMeta,\n features: Set<string>,\n): FormatMeta['expect'] {\n const e = { ...meta.expect };\n\n if (features.has('texture-formats-tier1') && TIER1_STORAGE.has(meta.format)) {\n e.storage = true;\n }\n if (features.has('rg11b10ufloat-renderable') && meta.format === 'rg11b10ufloat') {\n e.renderable = true;\n e.blendable = true;\n }\n if (features.has('bgra8unorm-storage') && meta.format === 'bgra8unorm') {\n e.storage = true;\n }\n if (features.has('float32-blendable') && FLOAT32_COLOR.has(meta.format)) {\n e.blendable = true;\n }\n\n // tier2 subsumes tier1 and extends read-write storage further. The exact list\n // is still moving between implementations, so this stops at the point where\n // extra storage capability is no longer treated as a discrepancy.\n if (features.has('texture-formats-tier2') && meta.kind === 'color') {\n e.storage = e.storage || TIER1_STORAGE.has(meta.format);\n }\n\n return e;\n}\n\n/**\n * Whether measuring more capability than the baseline should be reported.\n * With tier features on, the extended list varies per implementation and the\n * reports are noise rather than signal.\n */\nexport function toleratesExtraStorage(features: Set<string>): boolean {\n return features.has('texture-formats-tier1') || features.has('texture-formats-tier2');\n}\n\n/** sampleType for the bindGroupLayout entry */\nexport function sampleTypeOf(meta: FormatMeta): GPUTextureSampleType {\n if (meta.kind === 'depth') {\n // Stencil-only formats are read as uint\n return meta.hasDepth ? 'depth' : 'uint';\n }\n if (meta.texel === 'u32') return 'uint';\n if (meta.texel === 'i32') return 'sint';\n return meta.filterable ? 'float' : 'unfilterable-float';\n}\n\n/** WGSL texture declaration type */\nexport function wgslTextureType(meta: FormatMeta): string {\n if (meta.kind === 'depth' && meta.hasDepth) return 'texture_depth_2d';\n return `texture_2d<${meta.texel}>`;\n}\n","// WebGPU error capture.\n//\n// WebGPU reports most failures through error scopes rather than exceptions, so\n// \"createTexture returned an object\" guarantees nothing on its own. This wraps a\n// call in all three scope types and, where it matters, waits for the queue to\n// actually finish the work before judging. Skipping that order lets failures\n// slip through silently.\n//\n// Errors are kept structured rather than formatted into strings. A consumer\n// asking \"did this fail because the format is unsupported, or because we ran\n// out of memory?\" should not have to match on message text — that is the same\n// fragility that string-matching skipped shader cases had.\n\nimport type { ProbeError, ProbeErrorKind } from '../types.js';\n\nconst SCOPES: GPUErrorFilter[] = ['validation', 'out-of-memory', 'internal'];\n\nexport interface Captured<T> {\n value: T | null;\n errors: ProbeError[];\n ok: boolean;\n}\n\n/**\n * Run fn inside error scopes.\n * @param settle wait for submitted work to complete before collecting errors.\n * Required whenever the check actually draws something.\n */\nexport async function capture<T>(\n device: GPUDevice,\n fn: () => T | Promise<T>,\n settle = false,\n): Promise<Captured<T>> {\n for (const scope of SCOPES) device.pushErrorScope(scope);\n\n let value: T | null = null;\n const errors: ProbeError[] = [];\n\n try {\n value = await fn();\n } catch (e) {\n errors.push({ kind: 'exception', message: describe(e) });\n }\n\n if (settle && errors.length === 0) {\n try {\n await device.queue.onSubmittedWorkDone();\n } catch (e) {\n errors.push({ kind: 'queue', message: describe(e) });\n }\n }\n\n // Scopes must be popped in reverse order of pushing.\n for (let i = SCOPES.length - 1; i >= 0; i--) {\n try {\n const err = await device.popErrorScope();\n if (err) errors.push({ kind: SCOPES[i] as ProbeErrorKind, message: err.message });\n } catch (e) {\n // If the device is already gone, popErrorScope itself rejects.\n errors.push({ kind: 'scope-unavailable', message: describe(e) });\n }\n }\n\n return { value, errors, ok: errors.length === 0 && value !== null };\n}\n\n/** When only success or failure matters */\nexport async function works(\n device: GPUDevice,\n fn: () => unknown | Promise<unknown>,\n settle = false,\n): Promise<{ ok: boolean; errors: ProbeError[] }> {\n const r = await capture(device, async () => {\n const v = await fn();\n // capture() treats null as failure, so functions returning undefined need a value.\n return v === undefined ? true : v;\n }, settle);\n return { ok: r.ok, errors: r.errors };\n}\n\n/** Tag errors with the check that produced them */\nexport function atStage(stage: ProbeError['stage'], errors: ProbeError[]): ProbeError[] {\n return errors.map((e) => ({ ...e, stage }));\n}\n\n/** First error message, for places that need one line of explanation */\nexport function firstMessage(errors: ProbeError[]): string {\n return errors[0]?.message ?? 'no error reported';\n}\n\nfunction describe(e: unknown): string {\n if (e instanceof Error) return `${e.name}: ${e.message}`;\n return String(e);\n}\n\n/** Release GPU resources without caring whether they are already gone */\nexport function dispose(...resources: Array<{ destroy?: () => void } | null | undefined>): void {\n for (const r of resources) {\n try {\n r?.destroy?.();\n } catch {\n // Already destroyed, or the device died. Either way, nothing to do.\n }\n }\n}\n","// Texture format verification.\r\n//\r\n// \"adapter.features contains texture-compression-bc\" and \"this device can create\r\n// and sample a bc7 texture\" are separate claims. Only the second one is believed\r\n// here. Every entry is decided by actually creating the resource, building the\r\n// pipeline, and running the pass.\r\n\r\nimport type { FormatSupport, ProbeError } from '../types.js';\r\nimport { FORMATS, sampleTypeOf, wgslTextureType, type FormatMeta } from './format-table.js';\r\nimport { atStage, capture, dispose, works } from './errors.js';\r\n\r\nconst VERTEX_WGSL = `\r\n@vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {\r\n var p = array<vec2f, 3>(vec2f(-1., -1.), vec2f(3., -1.), vec2f(-1., 3.));\r\n return vec4f(p[i], 0., 1.);\r\n}`;\r\n\r\n/** Shared color target that verification results get drawn into */\r\ninterface Scratch {\r\n target: GPUTexture;\r\n view: GPUTextureView;\r\n}\r\n\r\nexport async function probeFormats(\r\n device: GPUDevice,\r\n declaredFeatures: Set<string>,\r\n only?: string[],\r\n onProgress?: (ratio: number) => void,\r\n): Promise<FormatSupport[]> {\r\n const list = only\r\n ? FORMATS.filter((f) => only.includes(f.format))\r\n : FORMATS;\r\n\r\n const scratchTex = device.createTexture({\r\n size: [4, 4],\r\n format: 'rgba8unorm',\r\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\r\n });\r\n const scratch: Scratch = { target: scratchTex, view: scratchTex.createView() };\r\n\r\n const out: FormatSupport[] = [];\r\n for (let i = 0; i < list.length; i++) {\r\n out.push(await probeOne(device, list[i], declaredFeatures, scratch));\r\n onProgress?.((i + 1) / list.length);\r\n }\r\n\r\n dispose(scratchTex);\r\n return out;\r\n}\r\n\r\nasync function probeOne(\r\n device: GPUDevice,\r\n meta: FormatMeta,\r\n declaredFeatures: Set<string>,\r\n scratch: Scratch,\r\n): Promise<FormatSupport> {\r\n const result: FormatSupport = {\r\n format: meta.format,\r\n requiresFeature: meta.requiresFeature,\r\n featureDeclared: meta.requiresFeature ? declaredFeatures.has(meta.requiresFeature) : true,\r\n creatable: false,\r\n sampleable: false,\r\n renderable: false,\r\n blendable: false,\r\n storageWritable: false,\r\n multisample4x: false,\r\n errors: [],\r\n };\r\n\r\n const [w, h] = meta.block ?? [4, 4];\r\n\r\n // 1. Can it be created at all\r\n const created = await capture(device, () =>\r\n device.createTexture({\r\n size: [w, h],\r\n format: meta.format as GPUTextureFormat,\r\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,\r\n }),\r\n );\r\n result.creatable = created.ok;\r\n if (!created.ok) {\r\n result.errors.push(...atStage('create', created.errors));\r\n // Nothing else is worth checking if it cannot even be created.\r\n return result;\r\n }\r\n const tex = created.value!;\r\n\r\n // 2. Can a shader read it\r\n const sampled = await probeSampleable(device, meta, tex, scratch);\r\n result.sampleable = sampled.ok;\r\n if (!sampled.ok) result.errors.push(...atStage('sample', sampled.errors));\r\n dispose(tex);\r\n\r\n // 3. Does it work as a render target / 4. does blending work\r\n if (meta.kind === 'compressed') {\r\n // Compressed formats cannot be render targets. Nothing to try.\r\n } else if (meta.kind === 'depth') {\r\n const r = await probeDepthRenderable(device, meta);\r\n result.renderable = r.ok;\r\n if (!r.ok) result.errors.push(...atStage('render', r.errors));\r\n } else {\r\n const r = await probeColorRenderable(device, meta, false);\r\n result.renderable = r.ok;\r\n if (!r.ok) result.errors.push(...atStage('render', r.errors));\r\n\r\n if (result.renderable) {\r\n const b = await probeColorRenderable(device, meta, true);\r\n result.blendable = b.ok;\r\n if (!b.ok) result.errors.push(...atStage('blend', b.errors));\r\n }\r\n }\r\n\r\n // 5. Does it work as a storage texture\r\n if (meta.kind === 'color') {\r\n const s = await probeStorage(device, meta);\r\n result.storageWritable = s.ok;\r\n if (!s.ok) result.errors.push(...atStage('storage', s.errors));\r\n }\r\n\r\n // 6. 4x MSAA\r\n if (result.renderable) {\r\n const m = await probeMultisample(device, meta);\r\n result.multisample4x = m.ok;\r\n if (!m.ok) result.errors.push(...atStage('msaa4x', m.errors));\r\n }\r\n\r\n return result;\r\n}\r\n\r\n// ── Individual checks ───────────────────────────────────\r\n\r\nasync function probeSampleable(\r\n device: GPUDevice,\r\n meta: FormatMeta,\r\n tex: GPUTexture,\r\n scratch: Scratch,\r\n): Promise<{ ok: boolean; errors: ProbeError[] }> {\r\n const needsSampler = meta.kind === 'compressed';\r\n const sampleType = sampleTypeOf(meta);\r\n\r\n return works(device, async () => {\r\n const entries: GPUBindGroupLayoutEntry[] = [{\r\n binding: 0,\r\n visibility: GPUShaderStage.FRAGMENT,\r\n texture: { sampleType, viewDimension: '2d' },\r\n }];\r\n if (needsSampler) {\r\n entries.push({\r\n binding: 1,\r\n visibility: GPUShaderStage.FRAGMENT,\r\n sampler: { type: meta.filterable ? 'filtering' : 'non-filtering' },\r\n });\r\n }\r\n\r\n const bgl = device.createBindGroupLayout({ entries });\r\n const module = device.createShaderModule({\r\n code: VERTEX_WGSL + sampleFragmentWGSL(meta, needsSampler),\r\n });\r\n\r\n const pipeline = device.createRenderPipeline({\r\n layout: device.createPipelineLayout({ bindGroupLayouts: [bgl] }),\r\n vertex: { module, entryPoint: 'vs' },\r\n fragment: { module, entryPoint: 'fs', targets: [{ format: 'rgba8unorm' }] },\r\n });\r\n\r\n // Formats carrying both depth and stencil need an explicit aspect on the\r\n // view. A plain createView() selects both and the binding is rejected.\r\n const viewDesc: GPUTextureViewDescriptor = {};\r\n if (meta.hasDepth && meta.hasStencil) viewDesc.aspect = 'depth-only';\r\n\r\n const bgEntries: GPUBindGroupEntry[] = [\r\n { binding: 0, resource: tex.createView(viewDesc) },\r\n ];\r\n let sampler: GPUSampler | undefined;\r\n if (needsSampler) {\r\n sampler = device.createSampler(\r\n meta.filterable ? { magFilter: 'linear', minFilter: 'linear' } : {},\r\n );\r\n bgEntries.push({ binding: 1, resource: sampler });\r\n }\r\n const bindGroup = device.createBindGroup({ layout: bgl, entries: bgEntries });\r\n\r\n const enc = device.createCommandEncoder();\r\n const pass = enc.beginRenderPass({\r\n colorAttachments: [{\r\n view: scratch.view,\r\n loadOp: 'clear',\r\n storeOp: 'store',\r\n clearValue: { r: 0, g: 0, b: 0, a: 1 },\r\n }],\r\n });\r\n pass.setPipeline(pipeline);\r\n pass.setBindGroup(0, bindGroup);\r\n pass.draw(3);\r\n pass.end();\r\n device.queue.submit([enc.finish()]);\r\n return true;\r\n }, true);\r\n}\r\n\r\nasync function probeColorRenderable(\r\n device: GPUDevice,\r\n meta: FormatMeta,\r\n blend: boolean,\r\n): Promise<{ ok: boolean; errors: ProbeError[] }> {\r\n // Held so the texture can be released after works() has awaited the queue.\r\n // Doing it in a dangling .then() left an unhandled rejection whenever the\r\n // device was lost — precisely the case the probe has to survive.\r\n let created: GPUTexture | null = null;\r\n\r\n const result = await works(device, async () => {\r\n const tex = device.createTexture({\r\n size: [4, 4],\r\n format: meta.format as GPUTextureFormat,\r\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\r\n });\r\n\r\n const target: GPUColorTargetState = { format: meta.format as GPUTextureFormat };\r\n if (blend) {\r\n target.blend = {\r\n color: { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },\r\n alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },\r\n };\r\n }\r\n\r\n const module = device.createShaderModule({\r\n code: VERTEX_WGSL + colorFragmentWGSL(meta),\r\n });\r\n const pipeline = device.createRenderPipeline({\r\n layout: 'auto',\r\n vertex: { module, entryPoint: 'vs' },\r\n fragment: { module, entryPoint: 'fs', targets: [target] },\r\n });\r\n\r\n const enc = device.createCommandEncoder();\r\n const pass = enc.beginRenderPass({\r\n colorAttachments: [{\r\n view: tex.createView(),\r\n loadOp: 'clear',\r\n storeOp: 'store',\r\n clearValue: { r: 0, g: 0, b: 0, a: 1 },\r\n }],\r\n });\r\n pass.setPipeline(pipeline);\r\n pass.draw(3);\r\n pass.end();\r\n device.queue.submit([enc.finish()]);\r\n created = tex;\r\n return true;\r\n }, true);\r\n\r\n dispose(created);\r\n return result;\r\n}\r\n\r\nasync function probeDepthRenderable(\r\n device: GPUDevice,\r\n meta: FormatMeta,\r\n): Promise<{ ok: boolean; errors: ProbeError[] }> {\r\n // Held so the texture can be released after works() has awaited the queue.\r\n // Doing it in a dangling .then() left an unhandled rejection whenever the\r\n // device was lost — precisely the case the probe has to survive.\r\n let created: GPUTexture | null = null;\r\n\r\n const result = await works(device, async () => {\r\n const tex = device.createTexture({\r\n size: [4, 4],\r\n format: meta.format as GPUTextureFormat,\r\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\r\n });\r\n\r\n const depthStencil: GPUDepthStencilState = {\r\n format: meta.format as GPUTextureFormat,\r\n };\r\n if (meta.hasDepth) {\r\n depthStencil.depthWriteEnabled = true;\r\n depthStencil.depthCompare = 'always';\r\n }\r\n\r\n const module = device.createShaderModule({ code: VERTEX_WGSL });\r\n // Depth-only pipeline — no color target, so the fragment stage is omitted.\r\n const pipeline = device.createRenderPipeline({\r\n layout: 'auto',\r\n vertex: { module, entryPoint: 'vs' },\r\n depthStencil,\r\n });\r\n\r\n const attachment: GPURenderPassDepthStencilAttachment = { view: tex.createView() };\r\n if (meta.hasDepth) {\r\n attachment.depthClearValue = 1;\r\n attachment.depthLoadOp = 'clear';\r\n attachment.depthStoreOp = 'store';\r\n }\r\n if (meta.hasStencil) {\r\n attachment.stencilClearValue = 0;\r\n attachment.stencilLoadOp = 'clear';\r\n attachment.stencilStoreOp = 'store';\r\n }\r\n\r\n const enc = device.createCommandEncoder();\r\n const pass = enc.beginRenderPass({\r\n colorAttachments: [],\r\n depthStencilAttachment: attachment,\r\n });\r\n pass.setPipeline(pipeline);\r\n pass.draw(3);\r\n pass.end();\r\n device.queue.submit([enc.finish()]);\r\n created = tex;\r\n return true;\r\n }, true);\r\n\r\n dispose(created);\r\n return result;\r\n}\r\n\r\nasync function probeStorage(\r\n device: GPUDevice,\r\n meta: FormatMeta,\r\n): Promise<{ ok: boolean; errors: ProbeError[] }> {\r\n // Held so the texture can be released after works() has awaited the queue.\r\n // Doing it in a dangling .then() left an unhandled rejection whenever the\r\n // device was lost — precisely the case the probe has to survive.\r\n let created: GPUTexture | null = null;\r\n\r\n const result = await works(device, async () => {\r\n const tex = device.createTexture({\r\n size: [4, 4],\r\n format: meta.format as GPUTextureFormat,\r\n usage: GPUTextureUsage.STORAGE_BINDING,\r\n });\r\n\r\n const vecType = meta.texel === 'u32' ? 'vec4u' : meta.texel === 'i32' ? 'vec4i' : 'vec4f';\r\n const module = device.createShaderModule({\r\n code: `\r\n@group(0) @binding(0) var t: texture_storage_2d<${meta.format}, write>;\r\n@compute @workgroup_size(1) fn cs() {\r\n textureStore(t, vec2i(0, 0), ${vecType}(${meta.texel === 'f32' ? '1., 0., 0., 1.' : '1, 0, 0, 1'}));\r\n}`,\r\n });\r\n\r\n const pipeline = device.createComputePipeline({\r\n layout: 'auto',\r\n compute: { module, entryPoint: 'cs' },\r\n });\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: [{ binding: 0, resource: tex.createView() }],\r\n });\r\n\r\n const enc = device.createCommandEncoder();\r\n const pass = enc.beginComputePass();\r\n pass.setPipeline(pipeline);\r\n pass.setBindGroup(0, bindGroup);\r\n pass.dispatchWorkgroups(1);\r\n pass.end();\r\n device.queue.submit([enc.finish()]);\r\n created = tex;\r\n return true;\r\n }, true);\r\n\r\n dispose(created);\r\n return result;\r\n}\r\n\r\nasync function probeMultisample(\r\n device: GPUDevice,\r\n meta: FormatMeta,\r\n): Promise<{ ok: boolean; errors: ProbeError[] }> {\r\n // Held so the texture can be released after works() has awaited the queue.\r\n // Doing it in a dangling .then() left an unhandled rejection whenever the\r\n // device was lost — precisely the case the probe has to survive.\r\n let created: GPUTexture | null = null;\r\n\r\n const result = await works(device, async () => {\r\n const tex = device.createTexture({\r\n size: [4, 4],\r\n format: meta.format as GPUTextureFormat,\r\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\r\n sampleCount: 4,\r\n });\r\n\r\n const module = device.createShaderModule({\r\n code: VERTEX_WGSL + (meta.kind === 'depth' ? '' : colorFragmentWGSL(meta)),\r\n });\r\n\r\n const desc: GPURenderPipelineDescriptor = {\r\n layout: 'auto',\r\n vertex: { module, entryPoint: 'vs' },\r\n multisample: { count: 4 },\r\n };\r\n if (meta.kind === 'depth') {\r\n const ds: GPUDepthStencilState = { format: meta.format as GPUTextureFormat };\r\n if (meta.hasDepth) {\r\n ds.depthWriteEnabled = true;\r\n ds.depthCompare = 'always';\r\n }\r\n desc.depthStencil = ds;\r\n } else {\r\n desc.fragment = {\r\n module,\r\n entryPoint: 'fs',\r\n targets: [{ format: meta.format as GPUTextureFormat }],\r\n };\r\n }\r\n const pipeline = device.createRenderPipeline(desc);\r\n\r\n const enc = device.createCommandEncoder();\r\n let pass: GPURenderPassEncoder;\r\n if (meta.kind === 'depth') {\r\n const attachment: GPURenderPassDepthStencilAttachment = { view: tex.createView() };\r\n if (meta.hasDepth) {\r\n attachment.depthClearValue = 1;\r\n attachment.depthLoadOp = 'clear';\r\n attachment.depthStoreOp = 'discard';\r\n }\r\n if (meta.hasStencil) {\r\n attachment.stencilClearValue = 0;\r\n attachment.stencilLoadOp = 'clear';\r\n attachment.stencilStoreOp = 'discard';\r\n }\r\n pass = enc.beginRenderPass({ colorAttachments: [], depthStencilAttachment: attachment });\r\n } else {\r\n pass = enc.beginRenderPass({\r\n colorAttachments: [{\r\n view: tex.createView(),\r\n loadOp: 'clear',\r\n storeOp: 'discard',\r\n clearValue: { r: 0, g: 0, b: 0, a: 1 },\r\n }],\r\n });\r\n }\r\n pass.setPipeline(pipeline);\r\n pass.draw(3);\r\n pass.end();\r\n device.queue.submit([enc.finish()]);\r\n created = tex;\r\n return true;\r\n }, true);\r\n\r\n dispose(created);\r\n return result;\r\n}\r\n\r\n// ── WGSL generation ─────────────────────────────────────\r\n\r\nfunction sampleFragmentWGSL(meta: FormatMeta, needsSampler: boolean): string {\r\n const texType = wgslTextureType(meta);\r\n const decl = `@group(0) @binding(0) var t: ${texType};`;\r\n const samplerDecl = needsSampler ? '@group(0) @binding(1) var s: sampler;' : '';\r\n\r\n let body: string;\r\n if (needsSampler) {\r\n // textureLoad is not available for compressed formats — only sampling is.\r\n body = 'return textureSample(t, s, vec2f(0.5, 0.5));';\r\n } else if (meta.kind === 'depth' && meta.hasDepth) {\r\n // textureLoad on texture_depth_2d yields a scalar f32.\r\n body = 'let v = textureLoad(t, vec2i(0, 0), 0);\\n return vec4f(v, 0., 0., 1.);';\r\n } else if (meta.texel === 'f32') {\r\n body = 'return textureLoad(t, vec2i(0, 0), 0);';\r\n } else {\r\n body = 'let v = textureLoad(t, vec2i(0, 0), 0);\\n return vec4f(f32(v.x), f32(v.y), f32(v.z), 1.);';\r\n }\r\n\r\n return `\r\n${decl}\r\n${samplerDecl}\r\n@fragment fn fs() -> @location(0) vec4f {\r\n ${body}\r\n}`;\r\n}\r\n\r\nfunction colorFragmentWGSL(meta: FormatMeta): string {\r\n // The fragment output type has to match the render target's texel type.\r\n if (meta.texel === 'u32') {\r\n return `\r\n@fragment fn fs() -> @location(0) vec4u {\r\n return vec4u(1u, 0u, 0u, 1u);\r\n}`;\r\n }\r\n if (meta.texel === 'i32') {\r\n return `\r\n@fragment fn fs() -> @location(0) vec4i {\r\n return vec4i(1, 0, 0, 1);\r\n}`;\r\n }\r\n return `\r\n@fragment fn fs() -> @location(0) vec4f {\r\n return vec4f(1., 0., 0., 1.);\r\n}`;\r\n}\r\n","// WGSL compilation checks.\r\n//\r\n// Every case here is valid WGSL, and implementations still disagree about them.\r\n// Chrome uses Dawn/Tint, Firefox uses wgpu/naga, Safari has its own compiler,\r\n// and each translates to a different backend language (HLSL/MSL/SPIR-V).\r\n// Compile time is measured too — on slow devices it is the main cause of\r\n// first-frame stalls.\r\n\r\nimport type { ProbeError, ShaderCase, ShaderMessage } from '../types.js';\r\nimport { capture } from './errors.js';\r\n\r\ninterface CaseSpec {\r\n id: string;\r\n description: string;\r\n code: string;\r\n /** Cases that also need pipeline creation to be attempted */\r\n pipeline?: 'compute' | 'render';\r\n /** Skipped when this feature is absent */\r\n requiresFeature?: string;\r\n}\r\n\r\nconst VS = `\r\n@vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {\r\n var p = array<vec2f, 3>(vec2f(-1., -1.), vec2f(3., -1.), vec2f(-1., 3.));\r\n return vec4f(p[i], 0., 1.);\r\n}`;\r\n\r\nconst CASES: CaseSpec[] = [\r\n {\r\n id: 'baseline',\r\n description: 'The simplest possible render pipeline — a reference point for the rest',\r\n pipeline: 'render',\r\n code: `${VS}\r\n@fragment fn fs() -> @location(0) vec4f { return vec4f(1.); }`,\r\n },\r\n {\r\n id: 'uniform-dynamic-index',\r\n description: 'Dynamic indexing into a uniform array — backends add clamping code or slow down',\r\n pipeline: 'render',\r\n code: `${VS}\r\nstruct Data { items: array<vec4f, 64> };\r\n@group(0) @binding(0) var<uniform> data: Data;\r\n@fragment fn fs(@builtin(position) pos: vec4f) -> @location(0) vec4f {\r\n let i = u32(pos.x) % 64u;\r\n return data.items[i];\r\n}`,\r\n },\r\n {\r\n id: 'nested-loop-break',\r\n description: 'Nested loops with conditional breaks — where control flow flattening diverges',\r\n pipeline: 'render',\r\n code: `${VS}\r\n@fragment fn fs(@builtin(position) pos: vec4f) -> @location(0) vec4f {\r\n var acc = 0.;\r\n for (var i = 0u; i < 8u; i++) {\r\n for (var j = 0u; j < 8u; j++) {\r\n if (f32(i * j) > pos.x) { break; }\r\n acc += 0.01;\r\n }\r\n if (acc > 0.5) { break; }\r\n }\r\n return vec4f(acc, 0., 0., 1.);\r\n}`,\r\n },\r\n {\r\n id: 'function-pointers',\r\n description: 'Passing var<function> pointers — naga and tint handle this differently',\r\n pipeline: 'render',\r\n code: `${VS}\r\nfn bump(p: ptr<function, vec3f>, amount: f32) {\r\n (*p) = (*p) + vec3f(amount);\r\n}\r\n@fragment fn fs() -> @location(0) vec4f {\r\n var v = vec3f(0.);\r\n bump(&v, 0.25);\r\n bump(&v, 0.25);\r\n return vec4f(v, 1.);\r\n}`,\r\n },\r\n {\r\n id: 'workgroup-atomics',\r\n description: 'Workgroup memory with atomics and barriers',\r\n pipeline: 'compute',\r\n code: `\r\nvar<workgroup> counter: atomic<u32>;\r\n@group(0) @binding(0) var<storage, read_write> out: array<u32>;\r\n@compute @workgroup_size(64) fn cs(@builtin(local_invocation_id) lid: vec3u) {\r\n if (lid.x == 0u) { atomicStore(&counter, 0u); }\r\n workgroupBarrier();\r\n atomicAdd(&counter, 1u);\r\n workgroupBarrier();\r\n if (lid.x == 0u) { out[0] = atomicLoad(&counter); }\r\n}`,\r\n },\r\n {\r\n id: 'storage-runtime-array',\r\n description: 'Runtime-sized array with arrayLength — exercises binding metadata handling',\r\n pipeline: 'compute',\r\n code: `\r\n@group(0) @binding(0) var<storage, read_write> data: array<f32>;\r\n@compute @workgroup_size(64) fn cs(@builtin(global_invocation_id) gid: vec3u) {\r\n let n = arrayLength(&data);\r\n if (gid.x < n) { data[gid.x] = f32(n); }\r\n}`,\r\n },\r\n {\r\n id: 'struct-alignment',\r\n description: 'Nested struct alignment and stride — a classic source of backend layout bugs',\r\n pipeline: 'compute',\r\n code: `\r\nstruct Inner { a: vec3f, b: f32 };\r\nstruct Outer { m: mat4x4f, items: array<Inner, 4>, flag: u32 };\r\n@group(0) @binding(0) var<storage, read_write> data: Outer;\r\n@compute @workgroup_size(1) fn cs() {\r\n data.items[0].b = data.m[0][0] + f32(data.flag);\r\n}`,\r\n },\r\n {\r\n id: 'override-constants',\r\n description: 'Override constants — pipeline-time specialization, unevenly supported',\r\n pipeline: 'compute',\r\n code: `\r\noverride tileSize: u32 = 8u;\r\n@group(0) @binding(0) var<storage, read_write> out: array<u32>;\r\n@compute @workgroup_size(1) fn cs() { out[0] = tileSize; }`,\r\n },\r\n {\r\n id: 'textureSampleLevel-uniform',\r\n description: 'Texture sampling under non-uniform control flow — uniformity analysis differs',\r\n pipeline: 'render',\r\n code: `${VS}\r\n@group(0) @binding(0) var t: texture_2d<f32>;\r\n@group(0) @binding(1) var s: sampler;\r\n@fragment fn fs(@builtin(position) pos: vec4f) -> @location(0) vec4f {\r\n var c = vec4f(0.);\r\n if (pos.x > 1.) {\r\n c = textureSampleLevel(t, s, vec2f(0.5), 0.);\r\n }\r\n return c;\r\n}`,\r\n },\r\n {\r\n id: 'long-unrolled',\r\n description: 'A large shader — exists to measure compile time',\r\n pipeline: 'render',\r\n code: `${VS}\r\n@fragment fn fs(@builtin(position) pos: vec4f) -> @location(0) vec4f {\r\n var acc = vec3f(0.);\r\n var p = pos.xyz * 0.01;\r\n${Array.from({ length: 64 }, (_, i) =>\r\n ` p = fract(p * 1.${(i % 9) + 1} + vec3f(${(i * 0.37).toFixed(3)}));\\n` +\r\n ` acc += p * ${(0.01 + i * 0.001).toFixed(4)};`).join('\\n')}\r\n return vec4f(acc, 1.);\r\n}`,\r\n },\r\n {\r\n id: 'f16-arithmetic',\r\n description: 'f16 arithmetic via shader-f16 — central to mobile performance, unevenly available',\r\n requiresFeature: 'shader-f16',\r\n pipeline: 'render',\r\n code: `enable f16;\r\n${VS}\r\n@fragment fn fs() -> @location(0) vec4f {\r\n var v: vec4<f16> = vec4<f16>(0.5h, 0.25h, 0.125h, 1.0h);\r\n v = v * 2.0h + vec4<f16>(0.1h);\r\n return vec4f(v);\r\n}`,\r\n },\r\n];\r\n\r\nexport async function probeShaders(\r\n device: GPUDevice,\r\n declaredFeatures: Set<string>,\r\n onProgress?: (ratio: number) => void,\r\n): Promise<ShaderCase[]> {\r\n const out: ShaderCase[] = [];\r\n\r\n for (let i = 0; i < CASES.length; i++) {\r\n const spec = CASES[i];\r\n onProgress?.((i + 1) / CASES.length);\r\n\r\n if (spec.requiresFeature && !declaredFeatures.has(spec.requiresFeature)) {\r\n out.push({\r\n id: spec.id,\r\n description: spec.description,\r\n skipped: true,\r\n compiled: false,\r\n pipelineCreated: false,\r\n messages: [{\r\n type: 'info',\r\n message: `skipped: ${spec.requiresFeature} not supported`,\r\n lineNum: 0,\r\n }],\r\n compileMs: 0,\r\n });\r\n continue;\r\n }\r\n\r\n out.push(await runCase(device, spec));\r\n }\r\n\r\n return out;\r\n}\r\n\r\nasync function runCase(device: GPUDevice, spec: CaseSpec): Promise<ShaderCase> {\r\n const result: ShaderCase = {\r\n id: spec.id,\r\n description: spec.description,\r\n skipped: false,\r\n compiled: false,\r\n pipelineCreated: false,\r\n messages: [],\r\n compileMs: 0,\r\n };\r\n\r\n const t0 = performance.now();\r\n const mod = await capture(device, () => device.createShaderModule({ code: spec.code }));\r\n\r\n if (!mod.ok || !mod.value) {\r\n result.compileMs = performance.now() - t0;\r\n result.messages.push(...mod.errors.map(toMessage));\r\n return result;\r\n }\r\n\r\n // Compilation is not finished until getCompilationInfo() resolves —\r\n // createShaderModule is asynchronous under the hood in most implementations.\r\n let info: GPUCompilationInfo | null = null;\r\n try {\r\n info = await mod.value.getCompilationInfo();\r\n } catch (e) {\r\n result.messages.push({ type: 'error', message: String(e), lineNum: 0 });\r\n }\r\n result.compileMs = performance.now() - t0;\r\n\r\n if (info) {\r\n for (const m of info.messages) {\r\n result.messages.push({\r\n type: m.type as ShaderMessage['type'],\r\n message: m.message,\r\n lineNum: m.lineNum,\r\n });\r\n }\r\n }\r\n result.compiled = !result.messages.some((m) => m.type === 'error');\r\n if (!result.compiled) return result;\r\n\r\n // Compiling does not mean a pipeline can be built — the real translation to\r\n // the backend language happens here.\r\n const built = await capture<GPUComputePipeline | GPURenderPipeline>(device, () => {\r\n if (spec.pipeline === 'compute') {\r\n return device.createComputePipelineAsync({\r\n layout: 'auto',\r\n compute: { module: mod.value!, entryPoint: 'cs' },\r\n });\r\n }\r\n return device.createRenderPipelineAsync({\r\n layout: 'auto',\r\n vertex: { module: mod.value!, entryPoint: 'vs' },\r\n fragment: {\r\n module: mod.value!,\r\n entryPoint: 'fs',\r\n targets: [{ format: 'rgba8unorm' }],\r\n },\r\n });\r\n });\r\n\r\n result.pipelineCreated = built.ok;\r\n if (!built.ok) result.messages.push(...built.errors.map(toMessage));\r\n\r\n return result;\r\n}\r\n\r\nfunction toMessage(e: ProbeError): ShaderMessage {\r\n return { type: 'error', message: e.message, lineNum: 0 };\r\n}\r\n","// Limit verification.\r\n//\r\n// adapter.limits.maxBufferSize may report 2GB while allocating that much gets\r\n// refused — which is the classic reason code written against declared values\r\n// dies on one specific device. This starts from the declared value and bisects\r\n// down to the real ceiling.\r\n\r\nimport type { LimitProbe, ProbeError } from '../types.js';\r\nimport { dispose, works } from './errors.js';\r\n\r\n/** Bisection step cap — trades precision against how long the probe takes */\r\nconst BISECT_STEPS = 10;\r\n\r\ntype Tester = (device: GPUDevice, value: number) => Promise<{ ok: boolean; errors: ProbeError[] }>;\r\n\r\ninterface LimitSpec {\r\n limit: string;\r\n test: Tester;\r\n /** Bisection floor — a value assumed to work */\r\n floor: number;\r\n}\r\n\r\nconst SPECS: LimitSpec[] = [\r\n {\r\n limit: 'maxBufferSize',\r\n floor: 256 * 1024 * 1024,\r\n test: (device, size) =>\r\n works(device, () => {\r\n const b = device.createBuffer({ size: align4(size), usage: GPUBufferUsage.STORAGE });\r\n // Release immediately — the question is whether it allocates, not whether it can be held.\r\n queueMicrotask(() => dispose(b));\r\n return b;\r\n }),\r\n },\r\n {\r\n limit: 'maxStorageBufferBindingSize',\r\n floor: 128 * 1024 * 1024,\r\n test: (device, size) =>\r\n works(device, () => {\r\n const buf = device.createBuffer({\r\n size: align4(size),\r\n usage: GPUBufferUsage.STORAGE,\r\n });\r\n const bgl = device.createBindGroupLayout({\r\n entries: [{\r\n binding: 0,\r\n visibility: GPUShaderStage.COMPUTE,\r\n buffer: { type: 'storage' },\r\n }],\r\n });\r\n const bg = device.createBindGroup({\r\n layout: bgl,\r\n entries: [{ binding: 0, resource: { buffer: buf, size: align4(size) } }],\r\n });\r\n queueMicrotask(() => dispose(buf));\r\n return bg;\r\n }),\r\n },\r\n {\r\n limit: 'maxUniformBufferBindingSize',\r\n floor: 16 * 1024,\r\n test: (device, size) =>\r\n works(device, () => {\r\n const buf = device.createBuffer({\r\n size: align16(size),\r\n usage: GPUBufferUsage.UNIFORM,\r\n });\r\n const bgl = device.createBindGroupLayout({\r\n entries: [{\r\n binding: 0,\r\n visibility: GPUShaderStage.FRAGMENT,\r\n buffer: { type: 'uniform' },\r\n }],\r\n });\r\n const bg = device.createBindGroup({\r\n layout: bgl,\r\n entries: [{ binding: 0, resource: { buffer: buf, size: align16(size) } }],\r\n });\r\n queueMicrotask(() => dispose(buf));\r\n return bg;\r\n }),\r\n },\r\n {\r\n limit: 'maxTextureDimension2D',\r\n floor: 2048,\r\n test: (device, size) =>\r\n works(device, () => {\r\n // [n, n] would be 1GB at n=16384. Width is what is being measured, so height stays 1.\r\n const t = device.createTexture({\r\n size: [Math.floor(size), 1],\r\n format: 'rgba8unorm',\r\n usage: GPUTextureUsage.TEXTURE_BINDING,\r\n });\r\n queueMicrotask(() => dispose(t));\r\n return t;\r\n }),\r\n },\r\n {\r\n limit: 'maxTextureArrayLayers',\r\n floor: 256,\r\n test: (device, layers) =>\r\n works(device, () => {\r\n const t = device.createTexture({\r\n size: [4, 4, Math.floor(layers)],\r\n format: 'rgba8unorm',\r\n usage: GPUTextureUsage.TEXTURE_BINDING,\r\n dimension: '2d',\r\n });\r\n queueMicrotask(() => dispose(t));\r\n return t;\r\n }),\r\n },\r\n {\r\n limit: 'maxComputeWorkgroupStorageSize',\r\n floor: 16 * 1024,\r\n test: (device, bytes) =>\r\n works(device, async () => {\r\n const count = Math.max(1, Math.floor(bytes / 16));\r\n const module = device.createShaderModule({\r\n code: `\r\nvar<workgroup> scratch: array<vec4f, ${count}>;\r\n@group(0) @binding(0) var<storage, read_write> out: array<f32>;\r\n@compute @workgroup_size(1) fn cs() {\r\n scratch[0] = vec4f(1.);\r\n out[0] = scratch[0].x;\r\n}`,\r\n });\r\n return device.createComputePipelineAsync({\r\n layout: 'auto',\r\n compute: { module, entryPoint: 'cs' },\r\n });\r\n }),\r\n },\r\n {\r\n limit: 'maxComputeInvocationsPerWorkgroup',\r\n floor: 64,\r\n test: (device, n) =>\r\n works(device, async () => {\r\n const module = device.createShaderModule({\r\n code: `\r\n@group(0) @binding(0) var<storage, read_write> out: array<u32>;\r\n@compute @workgroup_size(${Math.floor(n)}) fn cs(@builtin(local_invocation_id) lid: vec3u) {\r\n out[0] = lid.x;\r\n}`,\r\n });\r\n return device.createComputePipelineAsync({\r\n layout: 'auto',\r\n compute: { module, entryPoint: 'cs' },\r\n });\r\n }),\r\n },\r\n];\r\n\r\nexport async function probeLimits(\r\n device: GPUDevice,\r\n declared: Record<string, number>,\r\n onProgress?: (ratio: number) => void,\r\n): Promise<LimitProbe[]> {\r\n const out: LimitProbe[] = [];\r\n\r\n for (let i = 0; i < SPECS.length; i++) {\r\n const spec = SPECS[i];\r\n onProgress?.((i + 1) / SPECS.length);\r\n\r\n const declaredValue = declared[spec.limit];\r\n if (typeof declaredValue !== 'number' || declaredValue <= 0) continue;\r\n\r\n // Try the declared value as-is first. If it works, there is nothing to find.\r\n const full = await spec.test(device, declaredValue);\r\n if (full.ok) {\r\n out.push({\r\n limit: spec.limit,\r\n declared: declaredValue,\r\n achieved: declaredValue,\r\n honored: true,\r\n });\r\n continue;\r\n }\r\n\r\n // The declared value was refused. Find the real ceiling.\r\n const achieved = await bisect(device, spec, Math.min(spec.floor, declaredValue), declaredValue);\r\n out.push({\r\n limit: spec.limit,\r\n declared: declaredValue,\r\n achieved,\r\n honored: false,\r\n error: full.errors[0] ?? {\r\n kind: 'validation',\r\n message: 'refused for an unreported reason',\r\n stage: 'limit',\r\n },\r\n });\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/** lo is assumed to work and hi is known not to — find the boundary between them */\r\nasync function bisect(\r\n device: GPUDevice,\r\n spec: LimitSpec,\r\n lo: number,\r\n hi: number,\r\n): Promise<number> {\r\n // If even the floor fails, walk down until something works.\r\n let low = lo;\r\n let loOk = (await spec.test(device, low)).ok;\r\n while (!loOk && low > 1) {\r\n low = Math.floor(low / 2);\r\n loOk = (await spec.test(device, low)).ok;\r\n }\r\n if (!loOk) return 0;\r\n\r\n let high = hi;\r\n for (let i = 0; i < BISECT_STEPS && high - low > 1; i++) {\r\n const mid = low + Math.floor((high - low) / 2);\r\n if ((await spec.test(device, mid)).ok) low = mid;\r\n else high = mid;\r\n }\r\n return low;\r\n}\r\n\r\nconst align4 = (n: number) => Math.floor(n / 4) * 4;\r\nconst align16 = (n: number) => Math.floor(n / 16) * 16;\r\n","// GPU timing.\r\n//\r\n// With timestamp-query available this measures the time the GPU actually spent\r\n// in the pass; without it, it falls back to wall-clock around submission. The\r\n// two mean different things, so the result records which one produced a number.\r\n\r\nexport class GpuTimer {\r\n private querySet: GPUQuerySet | null = null;\r\n private resolveBuf: GPUBuffer | null = null;\r\n private readBuf: GPUBuffer | null = null;\r\n\r\n private constructor(public readonly available: boolean) {}\r\n\r\n static create(device: GPUDevice): GpuTimer {\r\n const has = device.features.has('timestamp-query');\r\n const timer = new GpuTimer(has);\r\n if (!has) return timer;\r\n\r\n try {\r\n timer.querySet = device.createQuerySet({ type: 'timestamp', count: 2 });\r\n timer.resolveBuf = device.createBuffer({\r\n size: 16,\r\n usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC,\r\n });\r\n timer.readBuf = device.createBuffer({\r\n size: 16,\r\n usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,\r\n });\r\n } catch {\r\n // If creation is refused, quietly drop to wall-clock mode.\r\n timer.dispose();\r\n return new GpuTimer(false);\r\n }\r\n return timer;\r\n }\r\n\r\n /** timestampWrites to put on a render pass descriptor */\r\n writes(): GPURenderPassTimestampWrites | undefined {\r\n if (!this.querySet) return undefined;\r\n return {\r\n querySet: this.querySet,\r\n beginningOfPassWriteIndex: 0,\r\n endOfPassWriteIndex: 1,\r\n };\r\n }\r\n\r\n /** Attach the resolve commands to an encoder whose pass has been recorded */\r\n resolve(encoder: GPUCommandEncoder): void {\r\n if (!this.querySet || !this.resolveBuf || !this.readBuf) return;\r\n encoder.resolveQuerySet(this.querySet, 0, 2, this.resolveBuf, 0);\r\n // Skip the copy while a previous read still holds the buffer mapped.\r\n if (this.readBuf.mapState === 'unmapped') {\r\n encoder.copyBufferToBuffer(this.resolveBuf, 0, this.readBuf, 0, 16);\r\n }\r\n }\r\n\r\n /**\r\n * Call after submitting. Returns GPU time in nanoseconds, or null if\r\n * unreadable. Nanoseconds are kept raw because quantization detection needs\r\n * the exact integer the browser reported.\r\n */\r\n async read(): Promise<number | null> {\r\n if (!this.readBuf || this.readBuf.mapState !== 'unmapped') return null;\r\n try {\r\n await this.readBuf.mapAsync(GPUMapMode.READ);\r\n const raw = new BigInt64Array(this.readBuf.getMappedRange().slice(0));\r\n this.readBuf.unmap();\r\n const ns = Number(raw[1] - raw[0]);\r\n // Zero is a meaningful reading, not a failure: it means the work finished\r\n // inside a single quantization bucket. Callers decide what to do with it.\r\n if (!Number.isFinite(ns) || ns < 0) return null;\r\n return ns;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n dispose(): void {\r\n try { this.querySet?.destroy(); } catch { /* already gone */ }\r\n try { this.resolveBuf?.destroy(); } catch { /* already gone */ }\r\n try { this.readBuf?.destroy(); } catch { /* already gone */ }\r\n this.querySet = null;\r\n this.resolveBuf = null;\r\n this.readBuf = null;\r\n }\r\n}\r\n\r\n/** Median */\r\nexport function median(values: number[]): number {\r\n if (values.length === 0) return 0;\r\n const s = [...values].sort((a, b) => a - b);\r\n const mid = s.length >> 1;\r\n return s.length % 2 ? s[mid] : (s[mid - 1] + s[mid]) / 2;\r\n}\r\n\r\n/** Coefficient of variation (stddev/mean). Above ~0.2 the number is not trustworthy */\r\nexport function variation(values: number[]): number {\r\n if (values.length < 2) return 0;\r\n const mean = values.reduce((a, b) => a + b, 0) / values.length;\r\n if (mean === 0) return 0;\r\n const varsum = values.reduce((a, b) => a + (b - mean) ** 2, 0) / (values.length - 1);\r\n return Math.sqrt(varsum) / mean;\r\n}\r\n","// Deciding whether a timer is quantized, from its readings alone.\n//\n// Split out from the benchmark code because it is pure arithmetic and the\n// judgement it makes is subtle enough to be worth testing directly: getting it\n// wrong made the same machine report a different timer on consecutive runs.\n\n/** Fraction of readings that must be multiples before a bucket is believed */\nconst AGREEMENT = 0.9;\n/** How far a reading may sit from a multiple, as a fraction of the bucket */\nconst TOLERANCE = 0.02;\n/** Fewer readings than this and there is nothing to conclude */\nconst MIN_READINGS = 4;\n\n/**\n * Whether readings are consistently multiples of the candidate bucket.\n *\n * Under real quantization every reading is a multiple of the bucket. On a timer\n * that is merely fine-grained, the smallest reading is just how long the\n * smallest workload happened to take and later readings fall wherever they like.\n */\nexport function behavesLikeBucket(readings: number[], bucket: number): boolean {\n if (bucket <= 0 || readings.length === 0) return false;\n\n const tolerance = bucket * TOLERANCE;\n let multiples = 0;\n for (const v of readings) {\n const remainder = v % bucket;\n if (remainder <= tolerance || remainder >= bucket - tolerance) multiples++;\n }\n\n // Allow a stray reading; demand the rest line up.\n return multiples / readings.length >= AGREEMENT;\n}\n\n/**\n * Estimate the quantization bucket from timer readings, or null when the timer\n * does not appear to be quantized at all.\n *\n * The candidate is the smaller of the smallest reading and the smallest gap\n * between distinct readings — under quantization both are multiples of the\n * bucket. It is then checked against every reading before being believed,\n * because a single number cannot distinguish a bucket from a short workload.\n */\nexport function estimateBucket(readings: number[]): number | null {\n const positive = readings.filter((v) => v > 0 && Number.isFinite(v));\n if (positive.length < MIN_READINGS) return null;\n\n const smallest = Math.min(...positive);\n\n const distinct = [...new Set(positive)].sort((a, b) => a - b);\n let smallestGap = Infinity;\n for (let i = 1; i < distinct.length; i++) {\n smallestGap = Math.min(smallestGap, distinct[i] - distinct[i - 1]);\n }\n\n const estimate = Math.min(smallest, smallestGap);\n if (!Number.isFinite(estimate) || estimate <= 0) return null;\n\n return behavesLikeBucket(positive, estimate) ? estimate : null;\n}\n","// Rendering microbenchmarks.\r\n//\r\n// The goal is not a single score but knowing which axis a device falls apart on.\r\n// A device that is cheap on draw calls but weak on fill rate needs the opposite\r\n// optimization from one that is the reverse, and a composite score erases that.\r\n//\r\n// Two things matter most for these numbers to mean anything:\r\n//\r\n// 1. Timestamp quantization. Browsers round timestamp-query results into coarse\r\n// buckets as a Spectre mitigation — tens to hundreds of microseconds. Work\r\n// shorter than one bucket collapses to the same value, so unrelated\r\n// benchmarks report identical numbers.\r\n// 2. Draw call and state change cost lives in browser validation and driver\r\n// calls, which barely register on GPU timestamps. That family is wall-clock.\r\n// 3. Repeated overdraw is not a reliable way to create fragment work. A\r\n// tile-based deferred GPU (Apple silicon, PowerVR) discards occluded opaque\r\n// draws before shading them, so stacking identical fullscreen passes\r\n// measures almost nothing there while measuring the full cost elsewhere —\r\n// the same benchmark ends up meaning different things per architecture.\r\n// Additive blending makes every draw contribute to the result, which\r\n// removes the option of discarding it.\r\n//\r\n// So each benchmark defines only a unit of work, and the repetition count is\r\n// raised automatically until the measurement clears the quantization bucket.\r\n//\r\n// The bucket size is measured rather than assumed: timing a pass that does\r\n// almost no GPU work reports the quantization floor directly. Every result then\r\n// records how many resolution units it spans, which is the only way to tell a\r\n// genuinely stable measurement from one flattened onto that floor — both show a\r\n// variation of zero.\r\n\r\nimport type { BenchResult, BenchmarkResults } from '../types.js';\r\nimport { GpuTimer, median, variation } from './timer.js';\r\nimport { dispose } from './errors.js';\r\nimport { estimateBucket } from './quantization.js';\r\n\r\nconst TARGET = 1024;\r\nconst WARMUP = 3;\r\n\r\n/** Scale repetitions until measurements exceed this, to clear quantization */\r\nconst TARGET_MS = 10;\r\n/** ...and until they span at least this many timer resolution units */\r\nconst MIN_TICKS = 100;\r\n/**\r\n * Wall-clock ticks required. Lower than MIN_TICKS because performance.now() is\r\n * coarse enough on some browsers (1ms in Safari) that demanding 100 would make\r\n * every draw-call benchmark take several seconds.\r\n */\r\nconst MIN_WALL_TICKS = 60;\r\n/** Below this many ticks a measurement is reported as quantized */\r\nconst QUANTIZED_BELOW_TICKS = 20;\r\n/** Cap on the repetition multiplier, so slow devices still finish */\r\nconst MAX_REPS = 2048;\r\n\r\ninterface BenchCtx {\r\n /** Record `reps` times the unit workload */\r\n record(encoder: GPUCommandEncoder, reps: number, writes?: GPURenderPassTimestampWrites): void;\r\n dispose?(): void;\r\n}\r\n\r\ninterface BenchSpec {\r\n id: string;\r\n description: string;\r\n /** Workload at reps = 1 */\r\n unitWorkload: number;\r\n unit: string;\r\n /** Draw call family is meaningless when measured as GPU time */\r\n timingMode: 'gpu-preferred' | 'wall-clock-only';\r\n setup(device: GPUDevice, view: GPUTextureView): Promise<BenchCtx>;\r\n}\r\n\r\nconst FULLSCREEN_VS = `\r\n@vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {\r\n var p = array<vec2f, 3>(vec2f(-1., -1.), vec2f(3., -1.), vec2f(-1., 3.));\r\n return vec4f(p[i], 0., 1.);\r\n}`;\r\n\r\n// Sending every vertex to the same position degenerates the triangle, leaving\r\n// draw call cost without any rasterization.\r\nconst DEGENERATE_VS = `\r\n@vertex fn vs() -> @builtin(position) vec4f {\r\n return vec4f(2., 2., 0.5, 1.);\r\n}`;\r\n\r\nconst SOLID_FS = `\r\n@fragment fn fs() -> @location(0) vec4f { return vec4f(0.25, 0.5, 0.75, 1.); }`;\r\n\r\n/**\r\n * Additive blending, used by every overdraw-based benchmark.\r\n *\r\n * Without it a deferred renderer is free to drop all but the last draw, since\r\n * an opaque fragment fully replaces what is under it. Accumulating means each\r\n * draw changes the result and none of them can be skipped.\r\n */\r\nconst ACCUMULATE: GPUBlendState = {\r\n color: { srcFactor: 'one', dstFactor: 'one', operation: 'add' },\r\n alpha: { srcFactor: 'one', dstFactor: 'one', operation: 'add' },\r\n};\r\n\r\n/** Every benchmark renders into the same target format */\r\nconst TARGET_FORMAT: GPUTextureFormat = 'rgba8unorm';\r\n\r\n/**\r\n * Build the render pipeline a benchmark needs.\r\n *\r\n * Takes WGSL source, or an already-created module for the cases that build\r\n * several pipelines from one shader shape.\r\n */\r\nfunction renderPipeline(\r\n device: GPUDevice,\r\n codeOrModule: string | GPUShaderModule,\r\n blend?: GPUBlendState,\r\n): Promise<GPURenderPipeline> {\r\n const module = typeof codeOrModule === 'string'\r\n ? device.createShaderModule({ code: codeOrModule })\r\n : codeOrModule;\r\n\r\n return device.createRenderPipelineAsync({\r\n layout: 'auto',\r\n vertex: { module, entryPoint: 'vs' },\r\n fragment: {\r\n module,\r\n entryPoint: 'fs',\r\n targets: [blend ? { format: TARGET_FORMAT, blend } : { format: TARGET_FORMAT }],\r\n },\r\n });\r\n}\r\n\r\nconst DRAWS_PER_REP = 2_000;\r\nconst TRIS_PER_REP = 100_000;\r\n\r\nconst SPECS: BenchSpec[] = [\r\n {\r\n id: 'drawcall-overhead',\r\n description: 'Empty draw calls — browser validation and driver call cost',\r\n unitWorkload: DRAWS_PER_REP,\r\n unit: 'draws/s',\r\n timingMode: 'wall-clock-only',\r\n setup: async (device, view) => {\r\n const pipeline = await renderPipeline(device, DEGENERATE_VS + SOLID_FS);\r\n return {\r\n record(encoder, reps, writes) {\r\n const pass = beginPass(encoder, view, writes);\r\n pass.setPipeline(pipeline);\r\n const n = DRAWS_PER_REP * reps;\r\n for (let i = 0; i < n; i++) pass.draw(3);\r\n pass.end();\r\n },\r\n };\r\n },\r\n },\r\n {\r\n id: 'pipeline-switch',\r\n description: 'Alternating between 8 pipelines per draw — state change cost',\r\n unitWorkload: DRAWS_PER_REP,\r\n unit: 'switches/s',\r\n timingMode: 'wall-clock-only',\r\n setup: async (device, view) => {\r\n const pipelines: GPURenderPipeline[] = [];\r\n for (let i = 0; i < 8; i++) {\r\n // Vary the shader slightly so these really are distinct pipelines.\r\n pipelines.push(await renderPipeline(device, DEGENERATE_VS + `\r\n@fragment fn fs() -> @location(0) vec4f { return vec4f(${(i / 8).toFixed(3)}, 0.5, 0.75, 1.); }`));\r\n }\r\n return {\r\n record(encoder, reps, writes) {\r\n const pass = beginPass(encoder, view, writes);\r\n const n = DRAWS_PER_REP * reps;\r\n for (let i = 0; i < n; i++) {\r\n pass.setPipeline(pipelines[i & 7]);\r\n pass.draw(3);\r\n }\r\n pass.end();\r\n },\r\n };\r\n },\r\n },\r\n {\r\n id: 'bindgroup-switch',\r\n description: 'Alternating between 64 bind groups per draw — resource binding cost',\r\n unitWorkload: DRAWS_PER_REP,\r\n unit: 'binds/s',\r\n timingMode: 'wall-clock-only',\r\n setup: async (device, view) => {\r\n const pipeline = await renderPipeline(device, `\r\nstruct U { tint: vec4f };\r\n@group(0) @binding(0) var<uniform> u: U;\r\n${DEGENERATE_VS}\r\n@fragment fn fs() -> @location(0) vec4f { return u.tint; }`);\r\n const layout = pipeline.getBindGroupLayout(0);\r\n const buffers: GPUBuffer[] = [];\r\n const groups: GPUBindGroup[] = [];\r\n for (let i = 0; i < 64; i++) {\r\n const buf = device.createBuffer({\r\n size: 16,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n device.queue.writeBuffer(buf, 0, new Float32Array([i / 64, 0.5, 0.75, 1]));\r\n buffers.push(buf);\r\n groups.push(device.createBindGroup({\r\n layout,\r\n entries: [{ binding: 0, resource: { buffer: buf } }],\r\n }));\r\n }\r\n return {\r\n record(encoder, reps, writes) {\r\n const pass = beginPass(encoder, view, writes);\r\n pass.setPipeline(pipeline);\r\n const n = DRAWS_PER_REP * reps;\r\n for (let i = 0; i < n; i++) {\r\n pass.setBindGroup(0, groups[i & 63]);\r\n pass.draw(3);\r\n }\r\n pass.end();\r\n },\r\n dispose: () => dispose(...buffers),\r\n };\r\n },\r\n },\r\n {\r\n id: 'fillrate',\r\n description: `${TARGET}x${TARGET} fullscreen overdraw, blended — fragment throughput`,\r\n unitWorkload: TARGET * TARGET * 8,\r\n unit: 'MPixel/s',\r\n timingMode: 'gpu-preferred',\r\n setup: async (device, view) => {\r\n const pipeline = await renderPipeline(device, FULLSCREEN_VS + SOLID_FS, ACCUMULATE);\r\n return {\r\n record(encoder, reps, writes) {\r\n const pass = beginPass(encoder, view, writes);\r\n pass.setPipeline(pipeline);\r\n const n = 8 * reps;\r\n for (let i = 0; i < n; i++) pass.draw(3);\r\n pass.end();\r\n },\r\n };\r\n },\r\n },\r\n {\r\n id: 'fragment-alu',\r\n description: 'Heavy per-pixel arithmetic — shader math, separated from fill rate',\r\n unitWorkload: TARGET * TARGET,\r\n unit: 'MPixel/s',\r\n timingMode: 'gpu-preferred',\r\n setup: async (device, view) => {\r\n const module = device.createShaderModule({\r\n code: FULLSCREEN_VS + `\r\n@fragment fn fs(@builtin(position) pos: vec4f) -> @location(0) vec4f {\r\n var p = pos.xyz * 0.001;\r\n var acc = 0.;\r\n for (var i = 0u; i < 64u; i++) {\r\n p = fract(p * 1.7 + vec3f(0.31, 0.17, 0.53));\r\n acc += dot(p, vec3f(0.33)) * exp(-p.x) + sqrt(abs(p.y));\r\n }\r\n return vec4f(acc * 0.01, p.y, p.z, 1.);\r\n}`,\r\n });\r\n const pipeline = await renderPipeline(device, module, ACCUMULATE);\r\n return {\r\n record(encoder, reps, writes) {\r\n const pass = beginPass(encoder, view, writes);\r\n pass.setPipeline(pipeline);\r\n for (let i = 0; i < reps; i++) pass.draw(3);\r\n pass.end();\r\n },\r\n };\r\n },\r\n },\r\n {\r\n id: 'triangle-throughput',\r\n description: 'Many small triangles — geometry throughput',\r\n unitWorkload: TRIS_PER_REP,\r\n unit: 'MTri/s',\r\n timingMode: 'gpu-preferred',\r\n setup: async (device, view) => {\r\n const module = device.createShaderModule({\r\n code: `\r\n@vertex fn vs(@builtin(vertex_index) vi: u32) -> @builtin(position) vec4f {\r\n let tri = vi / 3u;\r\n let corner = vi % 3u;\r\n // Scatter triangles across a grid — they must stay on screen to avoid culling.\r\n let gx = f32(tri % 1000u) / 1000. * 2. - 1.;\r\n let gy = f32((tri / 1000u) % 100u) / 100. * 2. - 1.;\r\n var off = array<vec2f, 3>(vec2f(0., 0.), vec2f(0.0015, 0.), vec2f(0., 0.0015));\r\n return vec4f(gx + off[corner].x, gy + off[corner].y, 0.5, 1.);\r\n}\r\n${SOLID_FS}`,\r\n });\r\n const pipeline = await renderPipeline(device, module);\r\n return {\r\n record(encoder, reps, writes) {\r\n const pass = beginPass(encoder, view, writes);\r\n pass.setPipeline(pipeline);\r\n // Each draw is heavy enough that draw call overhead is buried.\r\n for (let i = 0; i < reps; i++) pass.draw(TRIS_PER_REP * 3);\r\n pass.end();\r\n },\r\n };\r\n },\r\n },\r\n {\r\n id: 'texture-sampling',\r\n description: '32 texture samples per pixel — texture bandwidth',\r\n unitWorkload: TARGET * TARGET * 32,\r\n unit: 'GSample/s',\r\n timingMode: 'gpu-preferred',\r\n setup: async (device, view) => {\r\n const tex = device.createTexture({\r\n size: [512, 512],\r\n format: 'rgba8unorm',\r\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,\r\n });\r\n const pixels = new Uint8Array(512 * 512 * 4);\r\n for (let i = 0; i < pixels.length; i++) pixels[i] = (i * 37) & 0xff;\r\n device.queue.writeTexture({ texture: tex }, pixels, { bytesPerRow: 512 * 4 }, [512, 512]);\r\n\r\n const module = device.createShaderModule({\r\n code: `\r\n@group(0) @binding(0) var t: texture_2d<f32>;\r\n@group(0) @binding(1) var s: sampler;\r\n${FULLSCREEN_VS}\r\n@fragment fn fs(@builtin(position) pos: vec4f) -> @location(0) vec4f {\r\n var acc = vec4f(0.);\r\n let base = pos.xy / ${TARGET}.;\r\n for (var i = 0u; i < 32u; i++) {\r\n // Spread the coordinates so this does not all sit in cache.\r\n let uv = fract(base + vec2f(f32(i) * 0.137, f32(i) * 0.379));\r\n acc += textureSampleLevel(t, s, uv, 0.);\r\n }\r\n return acc * 0.03125;\r\n}`,\r\n });\r\n const pipeline = await renderPipeline(device, module, ACCUMULATE);\r\n const sampler = device.createSampler({ magFilter: 'linear', minFilter: 'linear' });\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: [\r\n { binding: 0, resource: tex.createView() },\r\n { binding: 1, resource: sampler },\r\n ],\r\n });\r\n return {\r\n record(encoder, reps, writes) {\r\n const pass = beginPass(encoder, view, writes);\r\n pass.setPipeline(pipeline);\r\n pass.setBindGroup(0, bindGroup);\r\n for (let i = 0; i < reps; i++) pass.draw(3);\r\n pass.end();\r\n },\r\n dispose: () => dispose(tex),\r\n };\r\n },\r\n },\r\n];\r\n\r\n/**\r\n * Measure performance.now()'s granularity by spinning until it changes.\r\n *\r\n * Browsers round this too — Safari to a full millisecond — which matters\r\n * because the draw-call benchmarks are wall-clock by design. A 10ms reading\r\n * against a 1ms clock carries barely more than one significant digit, and it\r\n * showed up as those benchmarks swinging ~70% between runs.\r\n */\r\nfunction wallClockResolutionMs(): number {\r\n let smallest = Infinity;\r\n for (let i = 0; i < 24; i++) {\r\n const start = performance.now();\r\n let next = start;\r\n // Spin until the clock advances; the jump is one tick.\r\n while (next === start) next = performance.now();\r\n smallest = Math.min(smallest, next - start);\r\n }\r\n return Number.isFinite(smallest) && smallest > 0 ? smallest : 0;\r\n}\r\n\r\n/**\r\n * Measure the GPU timer's granularity.\r\n *\r\n * Work shorter than one bucket reports as zero, so the approach is to grow a\r\n * trivial workload until readings first become non-zero. The smallest positive\r\n * reading bounds the bucket from above, and the smallest gap between distinct\r\n * readings usually lands on the bucket itself — quantized values are all\r\n * multiples of it. The tighter of the two is used.\r\n *\r\n * Returns null when the timer appears continuous (no quantization detected) or\r\n * when readings could not be obtained at all.\r\n */\r\nasync function calibrateResolution(\r\n device: GPUDevice,\r\n timer: GpuTimer,\r\n): Promise<number | null> {\r\n if (!timer.available) return null;\r\n\r\n const tex = device.createTexture({\r\n size: [256, 256],\r\n format: 'rgba8unorm',\r\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\r\n });\r\n const view = tex.createView();\r\n\r\n let pipeline: GPURenderPipeline;\r\n try {\r\n pipeline = await renderPipeline(device, FULLSCREEN_VS + SOLID_FS);\r\n } catch {\r\n dispose(tex);\r\n return null;\r\n }\r\n\r\n const readings: number[] = [];\r\n\r\n // Grow the workload until readings stop collapsing to zero.\r\n let draws = 1;\r\n for (let attempt = 0; attempt < 14; attempt++) {\r\n let positives = 0;\r\n\r\n for (let i = 0; i < 6; i++) {\r\n const enc = device.createCommandEncoder();\r\n const writes = timer.writes();\r\n const pass = beginPass(enc, view, writes);\r\n pass.setPipeline(pipeline);\r\n for (let d = 0; d < draws; d++) pass.draw(3);\r\n pass.end();\r\n if (writes) timer.resolve(enc);\r\n device.queue.submit([enc.finish()]);\r\n await device.queue.onSubmittedWorkDone();\r\n\r\n const ns = await timer.read();\r\n if (ns === null) continue;\r\n readings.push(ns);\r\n if (ns > 0) positives++;\r\n }\r\n\r\n // Enough non-zero readings to work with, and a few distinct values to\r\n // measure gaps between.\r\n if (positives >= 4 && new Set(readings.filter((v) => v > 0)).size >= 2) break;\r\n draws *= 4;\r\n }\r\n\r\n dispose(tex);\r\n\r\n // The estimate has to survive being checked against the readings before it is\r\n // reported. See quantization.ts — a single number cannot tell a bucket apart\r\n // from the cost of a short workload, and conflating them made the same\r\n // machine report a different timer on consecutive runs.\r\n return estimateBucket(readings);\r\n}\r\n\r\nexport async function runBenchmarks(\r\n device: GPUDevice,\r\n samples: number,\r\n onProgress?: (ratio: number) => void,\r\n): Promise<BenchmarkResults> {\r\n const started = performance.now();\r\n const timer = GpuTimer.create(device);\r\n\r\n const target = device.createTexture({\r\n size: [TARGET, TARGET],\r\n format: 'rgba8unorm',\r\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\r\n });\r\n const view = target.createView();\r\n\r\n const resolutionNs = await calibrateResolution(device, timer);\r\n const wallResolutionMs = wallClockResolutionMs();\r\n\r\n const results: BenchResult[] = [];\r\n for (let i = 0; i < SPECS.length; i++) {\r\n results.push(await measure(\r\n device, SPECS[i], view, timer, samples, resolutionNs, wallResolutionMs,\r\n ));\r\n onProgress?.((i + 1) / SPECS.length);\r\n }\r\n\r\n timer.dispose();\r\n dispose(target);\r\n\r\n return {\r\n results,\r\n timestampQuery: timer.available,\r\n timerResolutionNs: resolutionNs,\r\n wallClockResolutionMs: wallResolutionMs > 0 ? wallResolutionMs : null,\r\n totalMs: Math.round(performance.now() - started),\r\n };\r\n}\r\n\r\nasync function measure(\r\n device: GPUDevice,\r\n spec: BenchSpec,\r\n view: GPUTextureView,\r\n timer: GpuTimer,\r\n samples: number,\r\n resolutionNs: number | null,\r\n wallResolutionMs: number,\r\n): Promise<BenchResult> {\r\n const base: BenchResult = {\r\n id: spec.id,\r\n description: spec.description,\r\n medianMs: 0,\r\n minMs: 0,\r\n variation: 0,\r\n timing: 'wall-clock',\r\n samples: 0,\r\n repetitions: 0,\r\n };\r\n\r\n let ctx: BenchCtx;\r\n try {\r\n ctx = await spec.setup(device, view);\r\n } catch (e) {\r\n return { ...base, failed: `setup failed: ${describe(e)}` };\r\n }\r\n\r\n const useGpuTime = spec.timingMode === 'gpu-preferred' && timer.available;\r\n\r\n try {\r\n // Warm up — the first run mixes in shader translation and resource setup.\r\n for (let i = 0; i < WARMUP; i++) {\r\n const enc = device.createCommandEncoder();\r\n ctx.record(enc, 1);\r\n device.queue.submit([enc.finish()]);\r\n }\r\n await device.queue.onSubmittedWorkDone();\r\n\r\n // Auto-scale the repetition count. A measurement has to clear both a fixed\r\n // floor and a multiple of the timer resolution, because a coarse timer can\r\n // still flatten a 10ms measurement on some devices.\r\n // Each clock has its own floor. A GPU-timed benchmark is not bounded by\r\n // performance.now()'s granularity, and treating it as if it were just makes\r\n // the run longer for nothing.\r\n const targetMs = useGpuTime\r\n ? (resolutionNs\r\n ? Math.max(TARGET_MS, (resolutionNs * MIN_TICKS) / 1e6)\r\n // A continuous GPU timer imposes no floor of its own.\r\n : TARGET_MS)\r\n : Math.max(TARGET_MS, wallResolutionMs * MIN_WALL_TICKS);\r\n\r\n let reps = 1;\r\n for (let attempt = 0; attempt < 8; attempt++) {\r\n const { ms } = await once(device, ctx, reps, timer, useGpuTime);\r\n if (ms >= targetMs || reps >= MAX_REPS) break;\r\n // Estimate the multiplier needed, but do not jump too far at once.\r\n const factor = ms > 0.001 ? Math.ceil(targetMs / ms) : 8;\r\n reps = Math.min(MAX_REPS, reps * Math.max(2, Math.min(16, factor)));\r\n }\r\n\r\n const times: number[] = [];\r\n let gpuTimed = 0;\r\n for (let i = 0; i < samples; i++) {\r\n const { ms, fromGpu } = await once(device, ctx, reps, timer, useGpuTime);\r\n times.push(ms);\r\n if (fromGpu) gpuTimed++;\r\n }\r\n\r\n ctx.dispose?.();\r\n\r\n if (times.length === 0) {\r\n return { ...base, failed: 'no measurements were obtained' };\r\n }\r\n\r\n const fromGpuTimer = gpuTimed > times.length / 2;\r\n\r\n // Wall-clock samples carry scheduler noise the GPU timer does not, and it is\r\n // one-sided: an interrupted sample is slow, never fast. Dropping the\r\n // extremes keeps a single hiccup from moving the reported figure.\r\n const usable = fromGpuTimer ? times : trimExtremes(times);\r\n\r\n const med = median(usable);\r\n const workload = spec.unitWorkload * reps;\r\n const result: BenchResult = {\r\n ...base,\r\n medianMs: round(med, 4),\r\n minMs: round(Math.min(...usable), 4),\r\n variation: round(variation(usable), 3),\r\n timing: fromGpuTimer ? 'timestamp-query' : 'wall-clock',\r\n samples: usable.length,\r\n repetitions: reps,\r\n };\r\n\r\n // Both clocks quantize; which one applies depends on how this was timed.\r\n const tickSizeMs = fromGpuTimer\r\n ? (resolutionNs != null ? resolutionNs / 1e6 : null)\r\n : (wallResolutionMs > 0 ? wallResolutionMs : null);\r\n\r\n if (tickSizeMs) {\r\n const ticks = med / tickSizeMs;\r\n result.ticks = round(ticks, 1);\r\n result.quantized = ticks < QUANTIZED_BELOW_TICKS;\r\n }\r\n\r\n if (med > 0) {\r\n const perSecond = workload / (med / 1000);\r\n result.throughput = round(scaleTo(perSecond, spec.unit), 2);\r\n result.throughputUnit = spec.unit;\r\n }\r\n\r\n return result;\r\n } catch (e) {\r\n ctx.dispose?.();\r\n return { ...base, failed: `run failed: ${describe(e)}` };\r\n }\r\n}\r\n\r\n/** Run once, returning elapsed ms and whether that came from GPU timestamps */\r\nasync function once(\r\n device: GPUDevice,\r\n ctx: BenchCtx,\r\n reps: number,\r\n timer: GpuTimer,\r\n useGpuTime: boolean,\r\n): Promise<{ ms: number; fromGpu: boolean }> {\r\n const enc = device.createCommandEncoder();\r\n const writes = useGpuTime ? timer.writes() : undefined;\r\n const t0 = performance.now();\r\n ctx.record(enc, reps, writes);\r\n if (writes) timer.resolve(enc);\r\n device.queue.submit([enc.finish()]);\r\n await device.queue.onSubmittedWorkDone();\r\n const wall = performance.now() - t0;\r\n\r\n if (writes) {\r\n const gpuNs = await timer.read();\r\n // Zero means the work fit inside one bucket — no usable duration.\r\n if (gpuNs !== null && gpuNs > 0) return { ms: gpuNs / 1e6, fromGpu: true };\r\n }\r\n return { ms: wall, fromGpu: false };\r\n}\r\n\r\n/** Drop the highest and lowest sample, when there are enough to spare them */\r\nfunction trimExtremes(values: number[]): number[] {\r\n if (values.length < 5) return values;\r\n const sorted = [...values].sort((a, b) => a - b);\r\n return sorted.slice(1, -1);\r\n}\r\n\r\nfunction beginPass(\r\n encoder: GPUCommandEncoder,\r\n view: GPUTextureView,\r\n writes?: GPURenderPassTimestampWrites,\r\n): GPURenderPassEncoder {\r\n const desc: GPURenderPassDescriptor = {\r\n colorAttachments: [{\r\n view,\r\n loadOp: 'clear',\r\n storeOp: 'store',\r\n clearValue: { r: 0, g: 0, b: 0, a: 1 },\r\n }],\r\n };\r\n if (writes) desc.timestampWrites = writes;\r\n return encoder.beginRenderPass(desc);\r\n}\r\n\r\nfunction scaleTo(perSecond: number, unit: string): number {\r\n if (unit.startsWith('M')) return perSecond / 1e6;\r\n if (unit.startsWith('G')) return perSecond / 1e9;\r\n return perSecond;\r\n}\r\n\r\nfunction round(n: number, digits: number): number {\r\n const f = 10 ** digits;\r\n return Math.round(n * f) / f;\r\n}\r\n\r\nfunction describe(e: unknown): string {\r\n return e instanceof Error ? `${e.name}: ${e.message}` : String(e);\r\n}\r\n","// Discrepancy analysis.\r\n//\r\n// This is what gpu-atlas is for. It pulls out the places where declaration and\r\n// measurement disagree, and separates the ones that break code (breaking) from\r\n// the ones that only cost performance (degraded). What comes out is the list of\r\n// things to be careful about on this device.\r\n\r\nimport type {\r\n Discrepancy,\r\n FormatSupport,\r\n LimitProbe,\r\n ShaderCase,\r\n BenchmarkResults,\r\n} from '../types.js';\r\nimport { findMeta, expectationsFor, toleratesExtraStorage } from './format-table.js';\r\nimport { firstMessage } from './errors.js';\r\n\r\nexport function analyze(\r\n formats: FormatSupport[],\r\n shaders: ShaderCase[],\r\n limits: LimitProbe[],\r\n benchmarks: BenchmarkResults | null,\r\n features: Set<string>,\r\n): Discrepancy[] {\r\n const out: Discrepancy[] = [];\r\n const lenientStorage = toleratesExtraStorage(features);\r\n\r\n for (const f of formats) {\r\n const meta = findMeta(f.format);\r\n\r\n // The feature is declared, yet the texture cannot even be created.\r\n if (f.featureDeclared && !f.creatable) {\r\n out.push({\r\n kind: 'format-declared-not-usable',\r\n subject: f.format,\r\n detail: f.requiresFeature\r\n ? `${f.requiresFeature} is declared but createTexture fails: ${firstMessage(f.errors)}`\r\n : `core format, yet createTexture fails: ${firstMessage(f.errors)}`,\r\n severity: 'breaking',\r\n });\r\n continue;\r\n }\r\n\r\n // Creates fine but cannot be read from a shader — the nastier case, since it\r\n // tends to surface as something quietly rendering wrong.\r\n if (f.creatable && !f.sampleable) {\r\n out.push({\r\n kind: 'format-declared-not-usable',\r\n subject: f.format,\r\n detail: `the texture is created but shader sampling fails: ${firstMessage(f.errors)}`,\r\n severity: 'breaking',\r\n });\r\n }\r\n\r\n // A format behind an undeclared feature that works anyway. Nothing to rely\r\n // on, but it is a signal about how this implementation differs.\r\n if (!f.featureDeclared && f.creatable) {\r\n out.push({\r\n kind: 'format-usable-not-declared',\r\n subject: f.format,\r\n detail: `${f.requiresFeature} is not declared, yet texture creation succeeds`,\r\n severity: 'note',\r\n });\r\n }\r\n\r\n if (!meta || !f.creatable) continue;\r\n\r\n // Raise the core baseline by this device's features before comparing.\r\n const expect = expectationsFor(meta, features);\r\n\r\n if (expect.renderable && !f.renderable) {\r\n out.push({\r\n kind: 'format-declared-not-usable',\r\n subject: f.format,\r\n detail: `should be a valid render target per spec, but the render pass fails: ${firstMessage(f.errors)}`,\r\n severity: 'breaking',\r\n });\r\n }\r\n if (expect.blendable && f.renderable && !f.blendable) {\r\n out.push({\r\n kind: 'format-declared-not-usable',\r\n subject: f.format,\r\n detail: 'should support blending per spec, but creating a blend pipeline fails',\r\n severity: 'degraded',\r\n });\r\n }\r\n if (expect.storage && !f.storageWritable) {\r\n out.push({\r\n kind: 'format-declared-not-usable',\r\n subject: f.format,\r\n detail: `should work as a storage texture per spec, but fails: ${firstMessage(f.errors)}`,\r\n severity: 'breaking',\r\n });\r\n }\r\n // The other direction — an implementation more permissive than the baseline.\r\n if (!expect.storage && f.storageWritable && !lenientStorage) {\r\n out.push({\r\n kind: 'format-usable-not-declared',\r\n subject: f.format,\r\n detail: 'not a storage format per spec, yet it works on this implementation',\r\n severity: 'note',\r\n });\r\n }\r\n }\r\n\r\n for (const l of limits) {\r\n if (l.honored) continue;\r\n const ratio = l.declared > 0 ? l.achieved / l.declared : 0;\r\n out.push({\r\n kind: 'limit-not-honored',\r\n subject: l.limit,\r\n detail:\r\n `declares ${fmt(l.declared)} but only reaches ${fmt(l.achieved)}` +\r\n ` (${(ratio * 100).toFixed(0)}%). ${l.error?.message ?? ''}`.trimEnd(),\r\n // Below half, code written against the declared value simply dies.\r\n severity: ratio < 0.5 ? 'breaking' : 'degraded',\r\n });\r\n }\r\n\r\n for (const s of shaders) {\r\n if (s.skipped) continue;\r\n\r\n if (!s.compiled) {\r\n out.push({\r\n kind: 'shader-compile-failure',\r\n subject: s.id,\r\n detail: `${s.description} — compilation failed: ${firstError(s)}`,\r\n severity: 'breaking',\r\n });\r\n } else if (!s.pipelineCreated) {\r\n out.push({\r\n kind: 'shader-pipeline-failure',\r\n subject: s.id,\r\n detail: `${s.description} — compiled, but pipeline creation failed: ${firstError(s)}`,\r\n severity: 'breaking',\r\n });\r\n }\r\n }\r\n\r\n if (benchmarks) {\r\n for (const b of benchmarks.results) {\r\n if (b.failed) {\r\n out.push({\r\n kind: 'performance-cliff',\r\n subject: b.id,\r\n detail: `the benchmark did not complete: ${b.failed}`,\r\n severity: 'degraded',\r\n });\r\n } else if (b.quantized) {\r\n // A variation of zero here means the timer could not resolve the work,\r\n // not that the device was consistent. Reporting it as stable would be\r\n // the more misleading of the two options.\r\n out.push({\r\n kind: 'performance-cliff',\r\n subject: b.id,\r\n detail:\r\n `the measurement spans only ${b.ticks} timer resolution units, so it` +\r\n ' sits on the quantization floor. Treat this throughput as a lower' +\r\n ' bound rather than a measurement',\r\n severity: 'note',\r\n });\r\n } else if (b.variation > 0.35) {\r\n // Unstable measurement means throttling or competing load.\r\n out.push({\r\n kind: 'performance-cliff',\r\n subject: b.id,\r\n detail:\r\n `variation is ${(b.variation * 100).toFixed(0)}% — likely thermal` +\r\n ' throttling or external load. This number should not be trusted',\r\n severity: 'note',\r\n });\r\n }\r\n }\r\n }\r\n\r\n return out;\r\n}\r\n\r\nfunction firstError(s: ShaderCase): string {\r\n return s.messages.find((m) => m.type === 'error')?.message ?? 'no error message';\r\n}\r\n\r\nfunction fmt(n: number): string {\r\n if (n >= 1024 * 1024 * 1024) return `${(n / 1024 / 1024 / 1024).toFixed(2)}GB`;\r\n if (n >= 1024 * 1024) return `${(n / 1024 / 1024).toFixed(1)}MB`;\r\n if (n >= 1024) return `${(n / 1024).toFixed(1)}KB`;\r\n return String(n);\r\n}\r\n","// Identifying a device + browser combination.\n//\n// This is a grouping key, not an identifier for a person: it is derived only\n// from the adapter's self-description and the browser's major version, both of\n// which are shared by every machine of the same model.\n//\n// Width matters more than it looks. Collecting profiles in bulk is the point of\n// the project, and a 32-bit key collides with better-than-even odds once there\n// are ~77,000 of them. A collision silently merges two different devices, which\n// corrupts exactly the dataset the project exists to build, so the key is 128\n// bits.\n\n/** Bytes of hash to keep — 16 bytes renders as 32 hex characters */\nconst KEY_BYTES = 16;\n\nexport interface FingerprintInput {\n browser: string;\n browserVersion: string;\n vendor: string;\n architecture: string;\n device: string;\n description: string;\n}\n\nexport function fingerprintSource(input: FingerprintInput): string {\n // Only the major version: patch releases are the same device to us, and\n // including them would fragment the grouping for no benefit.\n const major = input.browserVersion.split('.')[0] ?? '';\n return [\n input.browser,\n major,\n input.vendor,\n input.architecture,\n input.device,\n input.description,\n ].join('|');\n}\n\nexport async function fingerprint(input: FingerprintInput): Promise<string> {\n const text = fingerprintSource(input);\n\n // SubtleCrypto needs a secure context. WebGPU does too, so this is available\n // on any device that produced a real profile — but a profile recording that\n // WebGPU was unavailable might come from somewhere it is not.\n const subtle = globalThis.crypto?.subtle;\n if (subtle) {\n try {\n const digest = await subtle.digest('SHA-256', new TextEncoder().encode(text));\n return toHex(new Uint8Array(digest).subarray(0, KEY_BYTES));\n } catch {\n // Fall through to the pure-JS path.\n }\n }\n\n return fnv1a128(text);\n}\n\n/**\n * FNV-1a widened to 128 bits by running four independent lanes with different\n * offset bases. Not a cryptographic hash — it only needs to spread device\n * descriptions well enough that collisions stay unlikely.\n */\nexport function fnv1a128(text: string): string {\n const PRIME = 0x01000193;\n const lanes = [0x811c9dc5, 0x1000193, 0xcbf29ce4, 0x84222325];\n\n for (let i = 0; i < text.length; i++) {\n const c = text.charCodeAt(i);\n for (let l = 0; l < lanes.length; l++) {\n // Perturb each lane differently so they do not collapse into one value.\n lanes[l] ^= c + l * 0x9e37;\n lanes[l] = Math.imul(lanes[l], PRIME) >>> 0;\n }\n }\n\n return lanes.map((v) => v.toString(16).padStart(8, '0')).join('');\n}\n\nfunction toHex(bytes: Uint8Array): string {\n let out = '';\n for (const b of bytes) out += b.toString(16).padStart(2, '0');\n return out;\n}\n","// Probe orchestration.\r\n\r\nimport type { AtlasProfile, ProbeOptions, VerifiedCapabilities } from '../types.js';\r\nimport { SCHEMA_VERSION } from '../types.js';\r\nimport { acquire, readEnvironment, WebGPUUnavailable } from './adapter.js';\r\nimport { probeFormats } from './formats.js';\r\nimport { probeShaders } from './shaders.js';\r\nimport { probeLimits } from './limits.js';\r\nimport { runBenchmarks } from './bench.js';\r\nimport { analyze } from './discrepancies.js';\r\nimport { fingerprint } from './fingerprint.js';\r\n\r\n/** Relative weight of each stage — benchmarking dominates */\r\nconst WEIGHTS = { formats: 0.25, shaders: 0.1, limits: 0.15, bench: 0.5 };\r\n\r\nexport async function probe(options: ProbeOptions = {}): Promise<AtlasProfile> {\r\n const {\r\n powerPreference,\r\n benchmark = true,\r\n onProgress,\r\n formats: onlyFormats,\r\n } = options;\r\n\r\n // Zero samples produce no measurement at all and a huge count runs for hours;\r\n // neither is a request worth honouring literally.\r\n const benchSamples = clamp(options.benchSamples ?? 7, 1, 99);\r\n\r\n const started = performance.now();\r\n const environment = await readEnvironment();\r\n\r\n const base: AtlasProfile = {\r\n schema: SCHEMA_VERSION,\r\n capturedAt: new Date().toISOString(),\r\n fingerprint: '',\r\n environment,\r\n adapter: null,\r\n declared: null,\r\n verified: null,\r\n benchmarks: null,\r\n discrepancies: [],\r\n elapsedMs: 0,\r\n };\r\n\r\n let acquired;\r\n try {\r\n acquired = await acquire(powerPreference);\r\n } catch (e) {\r\n return {\r\n ...base,\r\n unavailable: e instanceof WebGPUUnavailable ? e.message : describe(e),\r\n fingerprint: await fingerprint({\r\n browser: environment.browser,\r\n browserVersion: environment.browserVersion,\r\n vendor: '',\r\n architecture: '',\r\n device: '',\r\n description: '',\r\n }),\r\n elapsedMs: performance.now() - started,\r\n };\r\n }\r\n\r\n const { device, identity, declared, denied, lost } = acquired;\r\n\r\n // If the device dies partway, everything after that point is meaningless.\r\n // Just watch for it.\r\n let deviceLostReason: string | undefined;\r\n lost.then((info) => {\r\n deviceLostReason = `${info.reason}: ${info.message}`;\r\n });\r\n\r\n const declaredFeatures = new Set(declared.features);\r\n let done = 0;\r\n\r\n // A progress handler is UI code, and UI code throws. Losing a completed set\r\n // of measurements because a progress bar failed would be an absurd trade.\r\n const report = (stage: string, ratio: number) => {\r\n try {\r\n onProgress?.(stage, ratio);\r\n } catch {\r\n // The caller's problem, not the probe's.\r\n }\r\n };\r\n const step = (stage: string, weight: number) => (ratio: number) =>\r\n report(stage, done + weight * ratio);\r\n\r\n const verified: VerifiedCapabilities = {\r\n formats: [],\r\n shaders: [],\r\n limits: [],\r\n deviceLost: false,\r\n };\r\n\r\n try {\r\n report('formats', done);\r\n verified.formats = await probeFormats(\r\n device, declaredFeatures, onlyFormats, step('formats', WEIGHTS.formats),\r\n );\r\n done += WEIGHTS.formats;\r\n\r\n report('shaders', done);\r\n verified.shaders = await probeShaders(\r\n device, declaredFeatures, step('shaders', WEIGHTS.shaders),\r\n );\r\n done += WEIGHTS.shaders;\r\n\r\n report('limits', done);\r\n verified.limits = await probeLimits(\r\n device, declared.limits, step('limits', WEIGHTS.limits),\r\n );\r\n done += WEIGHTS.limits;\r\n } catch (e) {\r\n verified.deviceLost = true;\r\n verified.deviceLostReason = deviceLostReason ?? describe(e);\r\n }\r\n\r\n let benchmarks = null;\r\n if (benchmark && !verified.deviceLost) {\r\n report('benchmarks', done);\r\n try {\r\n benchmarks = await runBenchmarks(device, benchSamples, step('benchmarks', WEIGHTS.bench));\r\n } catch (e) {\r\n verified.deviceLostReason = deviceLostReason ?? describe(e);\r\n }\r\n }\r\n report('done', 1);\r\n\r\n if (deviceLostReason) {\r\n verified.deviceLost = true;\r\n verified.deviceLostReason = deviceLostReason;\r\n }\r\n\r\n const discrepancies = analyze(\r\n verified.formats, verified.shaders, verified.limits, benchmarks, declaredFeatures,\r\n );\r\n\r\n // Being refused what the adapter advertised is a discrepancy too.\r\n for (const d of denied) {\r\n discrepancies.push({\r\n kind: 'limit-not-honored',\r\n subject: d,\r\n detail: 'requestDevice refused values the adapter itself advertised',\r\n severity: 'degraded',\r\n });\r\n }\r\n\r\n const profile: AtlasProfile = {\r\n ...base,\r\n fingerprint: await fingerprint({\r\n browser: environment.browser,\r\n browserVersion: environment.browserVersion,\r\n vendor: identity.vendor,\r\n architecture: identity.architecture,\r\n device: identity.device,\r\n description: identity.description,\r\n }),\r\n adapter: identity,\r\n declared,\r\n verified,\r\n benchmarks,\r\n discrepancies,\r\n elapsedMs: Math.round(performance.now() - started),\r\n };\r\n\r\n device.destroy();\r\n return profile;\r\n}\r\n\r\nfunction clamp(value: number, low: number, high: number): number {\r\n if (!Number.isFinite(value)) return low;\r\n return Math.min(high, Math.max(low, Math.round(value)));\r\n}\r\n\r\nfunction describe(e: unknown): string {\r\n return e instanceof Error ? `${e.name}: ${e.message}` : String(e);\r\n}\r\n","// Comparing profiles across devices.\r\n//\r\n// A single profile answers \"what does this device do\". The question people\r\n// actually have is \"will my code run on the devices my users have, and what\r\n// budget do I get\" — and that only shows up when profiles are placed side by\r\n// side. Two devices already surface a 65x gap on one axis and 12x on another,\r\n// which no single profile could have revealed.\r\n\r\nimport type {\r\n AtlasProfile, BenchResult, FormatSupport, LimitProbe,\r\n} from './types.js';\r\nimport { MIN_COMPARABLE_BENCHMARK_SCHEMA } from './types.js';\r\n\r\nexport interface DeviceRef {\r\n fingerprint: string;\r\n /** Human-readable identity, e.g. \"qualcomm adreno-7xx / Samsung Internet 30\" */\r\n label: string;\r\n mobile: boolean;\r\n /** Index into the input array, for callers that need to get back to it */\r\n index: number;\r\n /** Schema version the profile was captured under */\r\n schema: number;\r\n /**\r\n * The profile predates the schema that made measurement trustworthiness\r\n * explicit, so its benchmark numbers are reported but never treated as\r\n * reliable. Capability data from such profiles is still comparable.\r\n */\r\n staleBenchmarks: boolean;\r\n}\r\n\r\nexport interface FeatureDiff {\r\n feature: string;\r\n supportedBy: string[];\r\n missingFrom: string[];\r\n}\r\n\r\n/** A texture capability that is not uniform across the compared devices */\r\nexport interface FormatDiff {\r\n format: string;\r\n capability: 'creatable' | 'sampleable' | 'renderable' | 'blendable'\r\n | 'storageWritable' | 'multisample4x';\r\n supportedBy: string[];\r\n missingFrom: string[];\r\n}\r\n\r\nexport interface LimitDiff {\r\n limit: string;\r\n /** fingerprint -> value actually achieved */\r\n values: Record<string, number>;\r\n min: number;\r\n max: number;\r\n /** max / min — how far apart the devices are */\r\n ratio: number;\r\n}\r\n\r\nexport interface BenchDiff {\r\n id: string;\r\n description: string;\r\n unit: string;\r\n /** fingerprint -> throughput, null when the benchmark did not produce one */\r\n values: Record<string, number | null>;\r\n fastest: string | null;\r\n slowest: string | null;\r\n /** fastest / slowest */\r\n ratio: number | null;\r\n /**\r\n * Devices whose measurement should not be trusted for this benchmark, either\r\n * because it sat on the quantization floor or because it was too unstable.\r\n * A ratio computed against these is not meaningful.\r\n */\r\n unreliable: string[];\r\n}\r\n\r\nexport interface Comparison {\r\n devices: DeviceRef[];\r\n /** Features present on some devices but not others */\r\n features: FeatureDiff[];\r\n /** Features every compared device has */\r\n sharedFeatures: string[];\r\n formats: FormatDiff[];\r\n limits: LimitDiff[];\r\n benchmarks: BenchDiff[];\r\n /** Profiles that could not be compared, and why */\r\n excluded: Array<{ index: number; reason: string }>;\r\n}\r\n\r\n/**\r\n * Lookup tables built once per profile.\r\n *\r\n * The naive version scanned the arrays inside the comparison loops, which is\r\n * fine for three profiles and quadratic for the collection this is meant to\r\n * grow into.\r\n */\r\ninterface Indexed {\r\n profile: AtlasProfile;\r\n features: Set<string>;\r\n formats: Map<string, FormatSupport>;\r\n limits: Map<string, LimitProbe>;\r\n benchmarks: Map<string, BenchResult>;\r\n}\r\n\r\nfunction index(p: AtlasProfile): Indexed {\r\n return {\r\n profile: p,\r\n features: new Set(p.declared!.features),\r\n formats: new Map(p.verified!.formats.map((f) => [f.format, f])),\r\n limits: new Map(p.verified!.limits.map((l) => [l.limit, l])),\r\n benchmarks: new Map((p.benchmarks?.results ?? []).map((r) => [r.id, r])),\r\n };\r\n}\r\n\r\nconst CAPABILITIES = [\r\n 'creatable', 'sampleable', 'renderable', 'blendable',\r\n 'storageWritable', 'multisample4x',\r\n] as const;\r\n\r\n/**\r\n * Above this coefficient of variation a benchmark is treated as unreliable.\r\n * Kept fairly tight: a 21.7% reading once slipped through on a benchmark that\r\n * turned out to be measuring nothing at all.\r\n */\r\nconst UNSTABLE_ABOVE = 0.15;\r\n\r\nexport function compareProfiles(profiles: AtlasProfile[]): Comparison {\r\n const devices: DeviceRef[] = [];\r\n const usable: AtlasProfile[] = [];\r\n const excluded: Comparison['excluded'] = [];\r\n\r\n // Fingerprints key every per-device value in the result, so two profiles\r\n // sharing one would silently overwrite each other rather than appear twice.\r\n // Comparing repeat runs of the same machine is a reasonable thing to want,\r\n // but it needs a different shape than this; saying so is better than\r\n // returning a quietly wrong table.\r\n const seen = new Set<string>();\r\n\r\n profiles.forEach((p, index) => {\r\n if (p.unavailable) {\r\n excluded.push({ index, reason: `WebGPU unavailable: ${p.unavailable}` });\r\n return;\r\n }\r\n if (!p.verified || !p.declared) {\r\n excluded.push({ index, reason: 'profile has no verified data' });\r\n return;\r\n }\r\n if (seen.has(p.fingerprint)) {\r\n excluded.push({\r\n index,\r\n reason: `duplicate of an earlier profile (${p.fingerprint.slice(0, 8)})`\r\n + ' — comparison keys values by fingerprint and cannot hold two',\r\n });\r\n return;\r\n }\r\n seen.add(p.fingerprint);\r\n const schema = typeof p.schema === 'number' ? p.schema : 0;\r\n devices.push({\r\n fingerprint: p.fingerprint,\r\n label: describeDevice(p),\r\n mobile: p.environment.mobile,\r\n index,\r\n schema,\r\n staleBenchmarks: schema < MIN_COMPARABLE_BENCHMARK_SCHEMA,\r\n });\r\n usable.push(p);\r\n });\r\n\r\n const indexed = usable.map(index);\r\n\r\n return {\r\n devices,\r\n ...diffFeatures(indexed),\r\n formats: diffFormats(indexed),\r\n limits: diffLimits(indexed),\r\n benchmarks: diffBenchmarks(indexed),\r\n excluded,\r\n };\r\n}\r\n\r\nexport function describeDevice(p: AtlasProfile): string {\r\n const gpu = [p.adapter?.vendor, p.adapter?.architecture]\r\n .filter(Boolean).join(' ') || p.adapter?.description || 'unknown GPU';\r\n const browser = [p.environment.browser, majorVersion(p.environment.browserVersion)]\r\n .filter(Boolean).join(' ');\r\n return browser ? `${gpu} / ${browser}` : gpu;\r\n}\r\n\r\n// ── Features ────────────────────────────────────────────\r\n\r\nfunction diffFeatures(profiles: Indexed[]): {\r\n features: FeatureDiff[];\r\n sharedFeatures: string[];\r\n} {\r\n const all = new Set<string>();\r\n for (const p of profiles) for (const f of p.features) all.add(f);\r\n\r\n const features: FeatureDiff[] = [];\r\n const shared: string[] = [];\r\n\r\n for (const feature of [...all].sort()) {\r\n const supportedBy: string[] = [];\r\n const missingFrom: string[] = [];\r\n for (const p of profiles) {\r\n (p.features.has(feature) ? supportedBy : missingFrom).push(p.profile.fingerprint);\r\n }\r\n if (missingFrom.length === 0) shared.push(feature);\r\n else features.push({ feature, supportedBy, missingFrom });\r\n }\r\n\r\n return { features, sharedFeatures: shared };\r\n}\r\n\r\n// ── Formats ─────────────────────────────────────────────\r\n\r\nfunction diffFormats(profiles: Indexed[]): FormatDiff[] {\r\n const all = new Set<string>();\r\n for (const p of profiles) {\r\n for (const format of p.formats.keys()) all.add(format);\r\n }\r\n\r\n const out: FormatDiff[] = [];\r\n\r\n for (const format of [...all].sort()) {\r\n for (const capability of CAPABILITIES) {\r\n const supportedBy: string[] = [];\r\n const missingFrom: string[] = [];\r\n\r\n for (const p of profiles) {\r\n const entry = p.formats.get(format);\r\n // A format the probe never checked is not evidence of anything.\r\n if (!entry) continue;\r\n (entry[capability] ? supportedBy : missingFrom).push(p.profile.fingerprint);\r\n }\r\n\r\n // Only differences are interesting; uniform support is the common case.\r\n if (supportedBy.length > 0 && missingFrom.length > 0) {\r\n out.push({ format, capability, supportedBy, missingFrom });\r\n }\r\n }\r\n }\r\n\r\n return out;\r\n}\r\n\r\n// ── Limits ──────────────────────────────────────────────\r\n\r\nfunction diffLimits(profiles: Indexed[]): LimitDiff[] {\r\n const all = new Set<string>();\r\n for (const p of profiles) for (const limit of p.limits.keys()) all.add(limit);\r\n\r\n const out: LimitDiff[] = [];\r\n\r\n for (const limit of [...all].sort()) {\r\n const values: Record<string, number> = {};\r\n for (const p of profiles) {\r\n const entry = p.limits.get(limit);\r\n if (entry) values[p.profile.fingerprint] = entry.achieved;\r\n }\r\n\r\n const nums = Object.values(values);\r\n if (nums.length < 2) continue;\r\n\r\n const min = Math.min(...nums);\r\n const max = Math.max(...nums);\r\n if (min === max) continue;\r\n\r\n out.push({ limit, values, min, max, ratio: min > 0 ? max / min : Infinity });\r\n }\r\n\r\n // Widest gaps first — those are the ones that break portability.\r\n return out.sort((a, b) => b.ratio - a.ratio);\r\n}\r\n\r\n// ── Benchmarks ──────────────────────────────────────────\r\n\r\nfunction diffBenchmarks(profiles: Indexed[]): BenchDiff[] {\r\n const all = new Map<string, BenchResult>();\r\n for (const p of profiles) {\r\n for (const [id, r] of p.benchmarks) {\r\n if (!all.has(id)) all.set(id, r);\r\n }\r\n }\r\n\r\n const out: BenchDiff[] = [];\r\n\r\n for (const [id, sample] of all) {\r\n const values: Record<string, number | null> = {};\r\n const unreliable: string[] = [];\r\n\r\n for (const p of profiles) {\r\n const fp = p.profile.fingerprint;\r\n const r = p.benchmarks.get(id);\r\n if (!r || r.failed || r.throughput == null) {\r\n values[fp] = null;\r\n continue;\r\n }\r\n values[fp] = r.throughput;\r\n\r\n // An older profile has no quantization data at all, so its numbers cannot\r\n // be vouched for — silence there means \"not recorded\", not \"fine\".\r\n const stale = (p.profile.schema ?? 0) < MIN_COMPARABLE_BENCHMARK_SCHEMA;\r\n if (stale || r.quantized || r.variation > UNSTABLE_ABOVE) unreliable.push(fp);\r\n }\r\n\r\n const present = Object.entries(values)\r\n .filter((e): e is [string, number] => e[1] != null);\r\n\r\n let fastest: string | null = null;\r\n let slowest: string | null = null;\r\n let ratio: number | null = null;\r\n\r\n if (present.length >= 2) {\r\n const sorted = [...present].sort((a, b) => b[1] - a[1]);\r\n fastest = sorted[0][0];\r\n slowest = sorted[sorted.length - 1][0];\r\n const hi = sorted[0][1];\r\n const lo = sorted[sorted.length - 1][1];\r\n ratio = lo > 0 ? hi / lo : null;\r\n }\r\n\r\n out.push({\r\n id,\r\n description: sample.description,\r\n unit: sample.throughputUnit ?? '',\r\n values,\r\n fastest,\r\n slowest,\r\n ratio,\r\n unreliable,\r\n });\r\n }\r\n\r\n // Biggest performance gaps first — that is where the portability risk is.\r\n return out.sort((a, b) => (b.ratio ?? 0) - (a.ratio ?? 0));\r\n}\r\n\r\n// ── Rendering ───────────────────────────────────────────\r\n\r\nexport interface FormatOptions {\r\n /**\r\n * Rows to print per section before summarising the rest. Sections are sorted\r\n * worst-first, so the truncated tail is the least interesting part — but a\r\n * hundred devices would otherwise produce thousands of lines.\r\n */\r\n limit?: number;\r\n}\r\n\r\n/**\r\n * Render a comparison as plain text. Useful for dropping into an issue, a\r\n * README, or a terminal without building a table by hand.\r\n */\r\nexport function formatComparison(c: Comparison, options: FormatOptions = {}): string {\r\n const limit = Math.max(1, options.limit ?? 20);\r\n const lines: string[] = [];\r\n const short = (fp: string) => fp.slice(0, 8);\r\n\r\n const truncate = <T>(items: T[]): { shown: T[]; hidden: number } => ({\r\n shown: items.slice(0, limit),\r\n hidden: Math.max(0, items.length - limit),\r\n });\r\n const noteHidden = (hidden: number, what: string) => {\r\n if (hidden > 0) lines.push(` ... and ${hidden} more ${what}`);\r\n };\r\n\r\n lines.push('Devices');\r\n for (const d of c.devices) {\r\n const flags = [\r\n d.mobile ? '(mobile)' : '',\r\n d.staleBenchmarks ? `(schema ${d.schema} - benchmarks not comparable)` : '',\r\n ].filter(Boolean).join(' ');\r\n lines.push(` ${short(d.fingerprint)} ${d.label}${flags ? ' ' + flags : ''}`);\r\n }\r\n\r\n if (c.benchmarks.length > 0) {\r\n lines.push('', 'Performance');\r\n const { shown: benches, hidden: hiddenBenches } = truncate(c.benchmarks);\r\n for (const b of benches) {\r\n const gap = b.ratio ? `${b.ratio.toFixed(1)}x` : '—';\r\n lines.push(` ${b.id} (${b.unit}) gap ${gap}`);\r\n for (const d of c.devices) {\r\n const v = b.values[d.fingerprint];\r\n const flag = b.unreliable.includes(d.fingerprint) ? ' [unreliable]' : '';\r\n lines.push(` ${short(d.fingerprint)} ${v != null ? v.toLocaleString() : '—'}${flag}`);\r\n }\r\n }\r\n noteHidden(hiddenBenches, 'benchmarks');\r\n }\r\n\r\n if (c.features.length > 0) {\r\n lines.push('', 'Features not available everywhere');\r\n const { shown, hidden } = truncate(c.features);\r\n for (const f of shown) {\r\n lines.push(` ${f.feature} missing on ${f.missingFrom.map(short).join(', ')}`);\r\n }\r\n noteHidden(hidden, 'features');\r\n }\r\n\r\n if (c.formats.length > 0) {\r\n lines.push('', 'Format capabilities that differ');\r\n const { shown, hidden } = truncate(c.formats);\r\n for (const f of shown) {\r\n lines.push(` ${f.format}.${f.capability} missing on ${f.missingFrom.map(short).join(', ')}`);\r\n }\r\n noteHidden(hidden, 'format capabilities');\r\n }\r\n\r\n if (c.limits.length > 0) {\r\n lines.push('', 'Limits that differ');\r\n const { shown: limitRows, hidden: hiddenLimits } = truncate(c.limits);\r\n for (const l of limitRows) {\r\n const gap = Number.isFinite(l.ratio) ? `${l.ratio.toFixed(1)}x` : '—';\r\n const vals = c.devices\r\n .map((d) => `${short(d.fingerprint)}=${l.values[d.fingerprint]?.toLocaleString() ?? '—'}`)\r\n .join(' ');\r\n lines.push(` ${l.limit} gap ${gap} ${vals}`);\r\n }\r\n noteHidden(hiddenLimits, 'limits');\r\n }\r\n\r\n if (c.excluded.length > 0) {\r\n lines.push('', 'Excluded');\r\n for (const e of c.excluded) lines.push(` profile #${e.index}: ${e.reason}`);\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\nfunction majorVersion(v: string): string {\r\n return v.split('.')[0] ?? '';\r\n}\r\n","// gpu-atlas — what WebGPU actually does on this device.\r\n//\r\n// import { probe } from 'gpu-atlas';\r\n// const profile = await probe();\r\n// console.log(profile.discrepancies); // what to watch out for here\r\n\r\nexport { probe } from './probe/index.js';\r\nexport { FORMATS, findMeta } from './probe/format-table.js';\r\nexport type { FormatMeta, FormatKind } from './probe/format-table.js';\r\n\r\nexport { compareProfiles, formatComparison, describeDevice } from './compare.js';\r\nexport type {\r\n Comparison,\r\n FormatOptions,\r\n DeviceRef,\r\n FeatureDiff,\r\n FormatDiff,\r\n LimitDiff,\r\n BenchDiff,\r\n} from './compare.js';\r\n\r\nexport { SCHEMA_VERSION, MIN_COMPARABLE_BENCHMARK_SCHEMA } from './types.js';\r\nexport type {\r\n AtlasProfile,\r\n ProbeOptions,\r\n EnvironmentInfo,\r\n AdapterIdentity,\r\n DeclaredCapabilities,\r\n VerifiedCapabilities,\r\n FormatSupport,\r\n ShaderCase,\r\n ShaderMessage,\r\n LimitProbe,\r\n BenchResult,\r\n BenchmarkResults,\r\n Discrepancy,\r\n DiscrepancyKind,\r\n} from './types.js';\r\n\r\nimport type { AtlasProfile, Discrepancy } from './types.js';\r\n\r\n/** Whether WebGPU could not be used at all */\r\nexport function isUnavailable(profile: AtlasProfile): boolean {\r\n return profile.unavailable !== undefined;\r\n}\r\n\r\n/** Only the problems that will actually break code */\r\nexport function breakingIssues(profile: AtlasProfile): Discrepancy[] {\r\n return profile.discrepancies.filter((d) => d.severity === 'breaking');\r\n}\r\n\r\n/** Formats verified to work as render targets on this device */\r\nexport function renderableFormats(profile: AtlasProfile): string[] {\r\n return (profile.verified?.formats ?? [])\r\n .filter((f) => f.renderable)\r\n .map((f) => f.format);\r\n}\r\n\r\n/** Formats verified to be readable from a shader */\r\nexport function sampleableFormats(profile: AtlasProfile): string[] {\r\n return (profile.verified?.formats ?? [])\r\n .filter((f) => f.sampleable)\r\n .map((f) => f.format);\r\n}\r\n\r\n/**\r\n * Pick the first candidate this device actually supports.\r\n * The result is measured rather than declared, so whatever comes back works.\r\n */\r\nexport function pickFormat(\r\n profile: AtlasProfile,\r\n candidates: string[],\r\n usage: 'render' | 'sample' | 'storage' = 'render',\r\n): string | null {\r\n const formats = profile.verified?.formats ?? [];\r\n for (const c of candidates) {\r\n const f = formats.find((x) => x.format === c);\r\n if (!f) continue;\r\n if (usage === 'render' && f.renderable) return c;\r\n if (usage === 'sample' && f.sampleable) return c;\r\n if (usage === 'storage' && f.storageWritable) return c;\r\n }\r\n return null;\r\n}\r\n\r\n/** Look up a benchmark result by id */\r\nexport function benchmark(profile: AtlasProfile, id: string) {\r\n return profile.benchmarks?.results.find((r) => r.id === id) ?? null;\r\n}\r\n"],"names":["SCHEMA_VERSION","MIN_COMPARABLE_BENCHMARK_SCHEMA","WebGPUUnavailable","message","acquire","powerPreference","adapter","identity","readIdentity","features","limits","limitsToRecord","denied","device","tryDevice","survivors","f","d","declared","safePreferredFormat","desc","info","legacy","out","key","supportedLimitKeys","v","keys","proto","k","readEnvironment","ua","uaData","platform","mobile","brand","brandVersion","high","primary","b","parsed","parseUA","patterns","name","re","m","color","format","texel","filterable","expect","requiresFeature","NO","R_B","R__","R_BS","R__S","___S","FORMATS","compressed","formats","feature","block","findMeta","TIER1_STORAGE","FLOAT32_COLOR","expectationsFor","meta","e","toleratesExtraStorage","sampleTypeOf","wgslTextureType","SCOPES","capture","fn","settle","scope","value","errors","describe","i","err","works","r","atStage","stage","firstMessage","dispose","resources","VERTEX_WGSL","probeFormats","declaredFeatures","only","onProgress","list","scratchTex","scratch","probeOne","result","w","h","created","tex","sampled","probeSampleable","probeDepthRenderable","probeColorRenderable","s","probeStorage","probeMultisample","needsSampler","sampleType","entries","bgl","module","sampleFragmentWGSL","pipeline","viewDesc","bgEntries","sampler","bindGroup","enc","pass","blend","target","colorFragmentWGSL","depthStencil","attachment","vecType","ds","decl","samplerDecl","body","VS","CASES","_","probeShaders","spec","runCase","t0","mod","toMessage","built","BISECT_STEPS","SPECS","size","align4","buf","bg","align16","t","layers","bytes","count","n","probeLimits","declaredValue","full","achieved","bisect","lo","hi","low","loOk","mid","GpuTimer","available","has","timer","encoder","raw","ns","median","values","a","variation","mean","varsum","AGREEMENT","TOLERANCE","MIN_READINGS","behavesLikeBucket","readings","bucket","tolerance","multiples","remainder","estimateBucket","positive","smallest","distinct","smallestGap","estimate","TARGET","WARMUP","TARGET_MS","MIN_TICKS","MIN_WALL_TICKS","QUANTIZED_BELOW_TICKS","MAX_REPS","FULLSCREEN_VS","DEGENERATE_VS","SOLID_FS","ACCUMULATE","TARGET_FORMAT","renderPipeline","codeOrModule","DRAWS_PER_REP","TRIS_PER_REP","view","reps","writes","beginPass","pipelines","layout","buffers","groups","pixels","wallClockResolutionMs","start","next","calibrateResolution","draws","attempt","positives","runBenchmarks","samples","started","resolutionNs","wallResolutionMs","results","measure","base","ctx","useGpuTime","targetMs","ms","once","factor","times","gpuTimed","fromGpu","fromGpuTimer","usable","trimExtremes","med","workload","round","tickSizeMs","ticks","perSecond","scaleTo","wall","gpuNs","unit","digits","analyze","shaders","benchmarks","lenientStorage","l","ratio","fmt","firstError","KEY_BYTES","fingerprintSource","input","major","fingerprint","text","subtle","digest","toHex","fnv1a128","lanes","c","WEIGHTS","probe","options","benchmark","onlyFormats","benchSamples","clamp","environment","acquired","lost","deviceLostReason","done","report","step","weight","verified","discrepancies","profile","index","p","CAPABILITIES","UNSTABLE_ABOVE","compareProfiles","profiles","devices","excluded","seen","schema","describeDevice","indexed","diffFeatures","diffFormats","diffLimits","diffBenchmarks","gpu","browser","majorVersion","all","shared","supportedBy","missingFrom","capability","entry","limit","nums","min","max","id","sample","unreliable","fp","present","fastest","slowest","sorted","formatComparison","lines","short","truncate","items","noteHidden","hidden","what","flags","benches","hiddenBenches","gap","flag","shown","limitRows","hiddenLimits","vals","isUnavailable","breakingIssues","renderableFormats","sampleableFormats","pickFormat","candidates","usage","x"],"mappings":"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"}
|