@photivra/engine 2.10.0 → 2.12.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.
Files changed (115) hide show
  1. package/CHANGELOG.md +156 -1
  2. package/CITATION.cff +1 -1
  3. package/NODE_SUPPORT.md +19 -3
  4. package/README.md +6 -6
  5. package/SECURITY.md +1 -1
  6. package/dist/core/portable-math.d.ts +6 -0
  7. package/dist/core/portable-math.js +39 -0
  8. package/dist/core/portable-math.js.map +1 -1
  9. package/dist/core/version.d.ts +1 -1
  10. package/dist/core/version.js +1 -1
  11. package/dist/core/version.js.map +1 -1
  12. package/dist/facade/chart-material-layers.d.ts +115 -0
  13. package/dist/facade/chart-material-layers.js +224 -0
  14. package/dist/facade/chart-material-layers.js.map +1 -0
  15. package/dist/facade/chart-radiance-batch.d.ts +8 -2
  16. package/dist/facade/chart-radiance-batch.js +11 -4
  17. package/dist/facade/chart-radiance-batch.js.map +1 -1
  18. package/dist/facade/chart-scenes.d.ts +134 -0
  19. package/dist/facade/chart-scenes.js +32 -22
  20. package/dist/facade/chart-scenes.js.map +1 -1
  21. package/dist/facade/diffraction-provider.d.ts +8 -2
  22. package/dist/facade/diffraction-provider.js +71 -2
  23. package/dist/facade/diffraction-provider.js.map +1 -1
  24. package/dist/facade/display-view-gpu-session.d.ts +18 -0
  25. package/dist/facade/display-view-gpu-session.js +280 -0
  26. package/dist/facade/display-view-gpu-session.js.map +1 -0
  27. package/dist/facade/display-view-gpu.d.ts +146 -0
  28. package/dist/facade/display-view-gpu.js +59 -0
  29. package/dist/facade/display-view-gpu.js.map +1 -0
  30. package/dist/facade/display-view.d.ts +48 -1
  31. package/dist/facade/display-view.js +7 -7
  32. package/dist/facade/display-view.js.map +1 -1
  33. package/dist/facade/expected-signal-setup.d.ts +5 -0
  34. package/dist/facade/expected-signal-setup.js +16 -0
  35. package/dist/facade/expected-signal-setup.js.map +1 -1
  36. package/dist/facade/expected-signal.d.ts +48 -3
  37. package/dist/facade/expected-signal.js +8 -0
  38. package/dist/facade/expected-signal.js.map +1 -1
  39. package/dist/facade/scene-radiance.d.ts +4 -2
  40. package/dist/facade/scene-radiance.js +7 -4
  41. package/dist/facade/scene-radiance.js.map +1 -1
  42. package/dist/facade/simulate-capture.d.ts +108 -8
  43. package/dist/facade/simulate-capture.js +226 -33
  44. package/dist/facade/simulate-capture.js.map +1 -1
  45. package/dist/facade/simulate-display-view.d.ts +31 -3
  46. package/dist/facade/simulate-display-view.js +73 -13
  47. package/dist/facade/simulate-display-view.js.map +1 -1
  48. package/dist/gpu/chart-composite-gpu.d.ts +119 -0
  49. package/dist/gpu/chart-composite-gpu.js +572 -0
  50. package/dist/gpu/chart-composite-gpu.js.map +1 -0
  51. package/dist/gpu/chart-radiance-gpu.d.ts +6 -6
  52. package/dist/gpu/chart-radiance-gpu.js +9 -11
  53. package/dist/gpu/chart-radiance-gpu.js.map +1 -1
  54. package/dist/gpu/display-view-chart-material-module.d.ts +10 -0
  55. package/dist/gpu/display-view-chart-material-module.js +58 -0
  56. package/dist/gpu/display-view-chart-material-module.js.map +1 -0
  57. package/dist/gpu/display-view-composite-material-module.d.ts +68 -0
  58. package/dist/gpu/display-view-composite-material-module.js +248 -0
  59. package/dist/gpu/display-view-composite-material-module.js.map +1 -0
  60. package/dist/gpu/display-view-quality-gpu.d.ts +185 -0
  61. package/dist/gpu/display-view-quality-gpu.js +1000 -0
  62. package/dist/gpu/display-view-quality-gpu.js.map +1 -0
  63. package/dist/gpu/display-view-speed-gpu.d.ts +156 -0
  64. package/dist/gpu/display-view-speed-gpu.js +524 -0
  65. package/dist/gpu/display-view-speed-gpu.js.map +1 -0
  66. package/dist/gpu/image-kernel-accelerator.d.ts +23 -4
  67. package/dist/gpu/image-kernel-accelerator.js +58 -10
  68. package/dist/gpu/image-kernel-accelerator.js.map +1 -1
  69. package/dist/gpu/image-kernel-execution.d.ts +55 -3
  70. package/dist/gpu/image-kernel-execution.js.map +1 -1
  71. package/dist/gpu/sensor-stage-gpu.d.ts +11 -0
  72. package/dist/gpu/sensor-stage-gpu.js +42 -13
  73. package/dist/gpu/sensor-stage-gpu.js.map +1 -1
  74. package/dist/gpu/webgpu-runtime.d.ts +4 -2
  75. package/dist/gpu/webgpu-runtime.js +13 -4
  76. package/dist/gpu/webgpu-runtime.js.map +1 -1
  77. package/dist/gpu/webgpu-switch.d.ts +4 -0
  78. package/dist/gpu/webgpu-switch.js +29 -0
  79. package/dist/gpu/webgpu-switch.js.map +1 -0
  80. package/dist/gpu/wgsl-chart-composite-kernel.d.ts +52 -0
  81. package/dist/gpu/wgsl-chart-composite-kernel.js +515 -0
  82. package/dist/gpu/wgsl-chart-composite-kernel.js.map +1 -0
  83. package/dist/gpu/wgsl-chart-kernel.d.ts +11 -9
  84. package/dist/gpu/wgsl-chart-kernel.js +33 -27
  85. package/dist/gpu/wgsl-chart-kernel.js.map +1 -1
  86. package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +95 -0
  87. package/dist/gpu/wgsl-display-view-quality-kernel.js +769 -0
  88. package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -0
  89. package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +75 -0
  90. package/dist/gpu/wgsl-display-view-speed-kernel.js +386 -0
  91. package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -0
  92. package/dist/gpu/wgsl-sensor-kernel.d.ts +28 -9
  93. package/dist/gpu/wgsl-sensor-kernel.js +94 -50
  94. package/dist/gpu/wgsl-sensor-kernel.js.map +1 -1
  95. package/dist/index.d.ts +5 -2
  96. package/dist/index.js +2 -0
  97. package/dist/index.js.map +1 -1
  98. package/dist/optics/defocus-disc-kernel.d.ts +61 -0
  99. package/dist/optics/defocus-disc-kernel.js +191 -0
  100. package/dist/optics/defocus-disc-kernel.js.map +1 -0
  101. package/docs/API_REFERENCE.md +47 -1
  102. package/docs/QUICK_START.md +150 -5
  103. package/docs/USAGE.md +81 -3
  104. package/docs/api/core-version.md +1 -1
  105. package/docs/api/exports.json +127 -2
  106. package/docs/api/facade-chart-material-layers.md +137 -0
  107. package/docs/api/facade-chart-radiance-batch.md +7 -2
  108. package/docs/api/facade-display-view-gpu.md +94 -0
  109. package/docs/api/facade-scene-radiance.md +3 -2
  110. package/docs/api/facade-simulate-capture.md +95 -11
  111. package/docs/api/facade-simulate-display-view.md +17 -2
  112. package/docs/api/gpu-image-kernel-accelerator.md +10 -3
  113. package/docs/api/gpu-image-kernel-execution.md +71 -4
  114. package/docs/api/gpu-webgpu-switch.md +23 -0
  115. package/package.json +3 -1
package/docs/USAGE.md CHANGED
@@ -1552,6 +1552,8 @@ console.log(components.value.composition.status); // "not-composed"
1552
1552
 
1553
1553
  The foundation deliberately **does not combine** geometric defocus and circular diffraction into a synthetic PSF, MTF, convolution kernel, combined blur radius or "lens sharpness" score.
1554
1554
 
1555
+ This foundation API is separate from the capture facade. With `lens.defocus` and `lens.diffraction` together, `simulateCapture` convolves each spectral node's diffraction kernel with the geometric defocus disc (#492). That is a labelled approximation, and it has its own `lens.defocus` assumption. See [Optics](QUICK_START.md#optics).
1556
+
1555
1557
  It already records field position, even though the current defocus and Airy diagnostics do not vary across the field. Future field-curvature, pupil-clipping, bokeh and aberration contributions can then use the same context without reinterpreting existing outputs.
1556
1558
 
1557
1559
  The spectral basis is explicitly monochromatic (one wavelength) for the Airy diagnostic. This does not create a spectral lens or sensor-colour model.
@@ -7300,18 +7302,19 @@ console.log(merged.raw.codes.length, merged.providerEvaluationCount);
7300
7302
  - By default they run on the float64 CPU reference.
7301
7303
  - If you opt in, they run on the `webgpu-f32` backend (WebGPU, 32-bit floats).
7302
7304
  - Every result's `execution` label names the backend that actually ran, any reason for falling back, and the error bound against the reference, stated in advance.
7305
+ - One boolean chooses: `{ webgpu: true }` asks for the GPU and runs the reference if it is missing; `{ webgpu: false }` is the reference. `setWebGpuEnabled(false)` turns the GPU off for the whole realm, whatever callers ask, and labels those results `webgpu-disabled`.
7303
7306
 
7304
7307
  See [WebGPU backend](https://github.com/Photivra/photivra/blob/main/docs/WEBGPU.md) for the bounds, the supported domain and the browser test.
7305
7308
 
7306
7309
  ```ts
7307
- import { createImageKernelAccelerator, calculateIrradianceConvolution } from "@photivra/engine";
7310
+ import { createImageKernelAccelerator, calculateIrradianceConvolution, getWebGpuEnabled, setWebGpuEnabled } from "@photivra/engine";
7308
7311
 
7309
7312
  const width = 16, height = 8, kernelRadius = 1;
7310
7313
  const input = { schemaVersion: "0.1.0" as const, width, height, kernelRadius, patchWidth: width, patchHeight: height,
7311
7314
  boundary: "zero-outside-grid" as const, samples: new Float64Array(width * height).fill(2),
7312
7315
  kernels: Float64Array.from([0, .1, 0, .1, .6, .1, 0, .1, 0]) };
7313
7316
 
7314
- const accelerator = await createImageKernelAccelerator({ backend: "webgpu-f32", fallback: "cpu-reference" });
7317
+ const accelerator = await createImageKernelAccelerator({ webgpu: true }); // the same as { backend: "webgpu-f32", fallback: "cpu-reference" }
7315
7318
  const result = await accelerator.convolveIrradiance(input);
7316
7319
  // Without WebGPU (e.g. Node) this ran the reference and says so.
7317
7320
  console.log(result.execution.backend, result.execution.fallbackReason, result.execution.bitIdenticalToReference);
@@ -7319,6 +7322,13 @@ console.log(result.execution.backend, result.execution.fallbackReason, result.ex
7319
7322
  const reference = calculateIrradianceConvolution(input).values;
7320
7323
  console.log(result.execution.backend === "cpu-reference" ? result.values.every((v, i) => v === reference[i]) : result.execution.errorBound);
7321
7324
  accelerator.dispose();
7325
+
7326
+ // The realm's switch: off, every request for the GPU runs the reference and says why.
7327
+ setWebGpuEnabled(false);
7328
+ const cpuOnly = await createImageKernelAccelerator({ webgpu: true });
7329
+ console.log(cpuOnly.backend, cpuOnly.fallbackReason, getWebGpuEnabled()); // "cpu-reference" "webgpu-disabled" false
7330
+ cpuOnly.dispose();
7331
+ setWebGpuEnabled(true);
7322
7332
  ```
7323
7333
 
7324
7334
  Two image-formation stages use the same accelerator:
@@ -7487,13 +7497,41 @@ const star = await simulateCapture({
7487
7497
  output: { width: 12, height: 8, toneCurve: "positive-reinhard-per-channel", whiteBalance: { kelvin: 5000 } }
7488
7498
  });
7489
7499
 
7490
- console.log(star.exposure.settings.shutterSeconds, star.exposure.ev100);
7500
+ console.log(star.exposure.settings.shutterSeconds, star.exposure.ev100, star.exposure.standardExposureDeviationStops);
7491
7501
  console.log(star.assumptions.filter((a) => a.kind === "default").map((a) => a.id));
7492
7502
  console.log(star.request.siteInput(0).environment.optics.nominalFNumber);
7493
7503
  ```
7494
7504
 
7495
7505
  In `aperture-priority` mode, the shutter comes from the meter (CIPA DC-004 relations S = 10/H and H = 0.65·L·t/N²) through
7496
7506
  `resolveAperturePriorityExposureMode()`.
7507
+ `exposure.standardExposureDeviationStops` is the exposure used minus the standard exposure for the metered luminance L, in stops,
7508
+ log₂(N²/t) − log₂(0.65·L·S/10) from the same relations: positive is darker (under), negative brighter (over). In an automatic
7509
+ mode it is minus the compensation plus any limit the resolver hit; it is `null` only for a scene with no metered luminance.
7510
+ The display view's `exposure` carries the same value.
7511
+
7512
+ With `exposure.iso: "auto"` (#516) the ISO is chosen too, in every mode, by the resolvers' Auto ISO branches
7513
+ ([Priority modes with Auto ISO](#priority-modes-with-auto-iso)). Aperture priority then needs the slowest shutter
7514
+ before the ISO rises, and takes the policy at the maximum ISO; the result reports the ISO, that it was automatic and
7515
+ what limited it. See [Auto ISO](QUICK_START.md#auto-iso-516).
7516
+
7517
+ ```ts
7518
+ import { prepareDisplayView, simulateCapture, type SimulateCaptureOptions } from "@photivra/engine";
7519
+
7520
+ const request: SimulateCaptureOptions = {
7521
+ exposure: { mode: "aperture-priority", iso: "auto", autoIso: { slowestPreferredShutterSeconds: 1 / 125 } },
7522
+ lens: { fNumber: 4 },
7523
+ scene: { preset: "siemens-star" },
7524
+ illuminanceLux: 50,
7525
+ output: { width: 16, height: 12 }
7526
+ };
7527
+ const capture = await simulateCapture(request);
7528
+ const { settings, isoControl, autoIso } = capture.exposure;
7529
+ // For example "ISO 3200 · Auto", and why: "iso-grid-quantization", or "iso-maximum" with the shutter held.
7530
+ console.log(`ISO ${settings.iso} · ${isoControl === "automatic" ? "Auto" : ""}`, autoIso?.limitingConstraint, autoIso?.afterMaximumIsoFallbackUsed);
7531
+ // The display view of the same request resolves the same exposure.
7532
+ const view = await (await prepareDisplayView(request)).render({ width: 8, height: 6 });
7533
+ console.log(view.exposure.settings.iso === settings.iso);
7534
+ ```
7497
7535
 
7498
7536
  The chart presets are also available on their own:
7499
7537
 
@@ -7516,6 +7554,27 @@ const view = await simulateDisplayView({ scene: { preset: "slanted-edge" }, sens
7516
7554
  console.log(view.kind, view.view.scaleX, view.assumptions.find((a) => a.id === "view.definition")?.value);
7517
7555
  ```
7518
7556
 
7557
+ #### Rendering a prepared view on the GPU (2.11, #481)
7558
+
7559
+ `prepareDisplayView(request, { gpu })` chooses the renderer: `"off"` (the default) is the CPU reference, `"auto"` the GPU
7560
+ when a conforming device is available and the request is supported (else the CPU, labelled), `"require"` fails instead of
7561
+ falling back. `gpuDevice` hands the view a worker's `navigator.gpu` or an `ImageKernelAccelerator` whose device it shares.
7562
+ Every render says which path ran in `diagnostics.fast.execution`, in the accelerator's words. No GPU display-view renderer
7563
+ exists yet (#478), so today `"auto"` runs the CPU reference labelled `unsupported-on-backend` without requesting a device;
7564
+ see [Rendering on the GPU](https://github.com/Photivra/photivra/blob/main/docs/DISPLAY_VIEW.md#rendering-on-the-gpu).
7565
+
7566
+ ```ts
7567
+ import { prepareDisplayView, type SimulateCaptureOptions } from "@photivra/engine";
7568
+
7569
+ const request: SimulateCaptureOptions = { scene: { preset: "siemens-star" }, sensor: { pixelPitchMicrometers: 4 }, output: { width: 600, height: 400 } };
7570
+ const prepared = await prepareDisplayView(request, { gpu: "auto" }); // acquisition failures fall back; with "require" they throw here
7571
+ const tile = await prepared.render({ width: 300, height: 200, region: { x: 120, y: 80, width: 32, height: 32 } });
7572
+ const ran = tile.diagnostics.fast.execution;
7573
+ // "cpu-reference" when the reference ran (and why), "webgpu-f32" with its bound and adapter when the GPU did.
7574
+ console.log(ran.backend, ran.fallbackReason, ran.assurance, ran.errorBound, ran.adapter, tile.diagnostics.fast.assurance);
7575
+ prepared.dispose(); // releases a device the view acquired; a shared accelerator's device stays its owner's
7576
+ ```
7577
+
7519
7578
  #### Sharing AHD correction states between workers
7520
7579
 
7521
7580
  With `output.demosaic: "ahd"`, low-signal display pixels read correction states that each realm (a page, a Web Worker)
@@ -7592,6 +7651,25 @@ const barrel = await simulateCapture({
7592
7651
  console.log(barrel.request.siteInput(0).environment.lensFieldMapping?.distortion.kind);
7593
7652
  ```
7594
7653
 
7654
+ `lens.defocus: { model: "geometric-disc" }` (#492) renders defocus of the flat scene plane when
7655
+ `lens.focusDistanceM` differs from `subjectDistanceM`. The thin-lens blur circle becomes a uniform disc on the site
7656
+ lattice, and the capture convolves the scene radiance with it, which is a geometric approximation. With
7657
+ `lens.diffraction`, each spectral node's diffraction kernel is convolved with the disc, which is a further
7658
+ approximation. The `lens.defocus` assumption records the diameter in µm and in sites, the kernel radius and the
7659
+ execution. `simulateDisplayView` does not render it yet. See [Optics](QUICK_START.md#optics).
7660
+
7661
+ ```ts
7662
+ import { simulateCapture } from "@photivra/engine";
7663
+
7664
+ const blurred = await simulateCapture({
7665
+ scene: { preset: "slanted-edge" },
7666
+ subjectDistanceM: 2,
7667
+ lens: { focalLengthMm: 50, fNumber: 4, focusDistanceM: 1.8, defocus: { model: "geometric-disc" } },
7668
+ output: { width: 16, height: 12 }
7669
+ });
7670
+ console.log(blurred.assumptions.find((a) => a.id === "lens.defocus")?.value); // diameterSites ≈ 5.95, kernelRadiusSites 3
7671
+ ```
7672
+
7595
7673
  `motion.angularVelocityRadPerSec` rotates the camera during the exposure (8 time midpoints by
7596
7674
  default). `motion.shutter: "rolling"` derives each site's exposure window from the body's rolling
7597
7675
  readout, with `resolveElectronicRollingShutterExposureSchedule`. See [Motion](QUICK_START.md#motion).
@@ -11,5 +11,5 @@ version they were made with. Proof-of-concept (POC), schema and model contracts
11
11
  own versions. Release checks confirm it matches package.json and the packed package.
12
12
 
13
13
  ```ts
14
- ENGINE_API_VERSION = "2.10.0" as const
14
+ ENGINE_API_VERSION = "2.12.0" as const
15
15
  ```
@@ -1,6 +1,6 @@
1
1
  {
2
- "packageVersion": "2.10.0",
3
- "engineApiVersion": "2.10.0",
2
+ "packageVersion": "2.12.0",
3
+ "engineApiVersion": "2.12.0",
4
4
  "exports": [
5
5
  {
6
6
  "name": "AbsoluteUncertaintyEstimate",
@@ -1827,6 +1827,16 @@
1827
1827
  "source": "src/facade/chart-scenes.ts",
1828
1828
  "kind": "runtime"
1829
1829
  },
1830
+ {
1831
+ "name": "CHART_MASK_INDEX_GRAIN",
1832
+ "source": "src/facade/chart-material-layers.ts",
1833
+ "kind": "runtime"
1834
+ },
1835
+ {
1836
+ "name": "CHART_MATERIAL_LAYER_LIMITS",
1837
+ "source": "src/facade/chart-material-layers.ts",
1838
+ "kind": "runtime"
1839
+ },
1830
1840
  {
1831
1841
  "name": "CHART_RADIANCE_BATCH_LIMITS",
1832
1842
  "source": "src/facade/chart-radiance-batch.ts",
@@ -1862,6 +1872,21 @@
1862
1872
  "source": "src/facade/chart-scenes.ts",
1863
1873
  "kind": "type"
1864
1874
  },
1875
+ {
1876
+ "name": "ChartCompositeProbeComponent",
1877
+ "source": "src/gpu/image-kernel-execution.ts",
1878
+ "kind": "type"
1879
+ },
1880
+ {
1881
+ "name": "ChartCompositeProbeMismatch",
1882
+ "source": "src/gpu/image-kernel-execution.ts",
1883
+ "kind": "type"
1884
+ },
1885
+ {
1886
+ "name": "ChartCompositeProbeRecord",
1887
+ "source": "src/gpu/image-kernel-execution.ts",
1888
+ "kind": "type"
1889
+ },
1865
1890
  {
1866
1891
  "name": "ChartElementScene",
1867
1892
  "source": "src/facade/chart-scenes.ts",
@@ -1872,6 +1897,31 @@
1872
1897
  "source": "src/facade/subject-framing.ts",
1873
1898
  "kind": "type"
1874
1899
  },
1900
+ {
1901
+ "name": "ChartMaskAnnulus",
1902
+ "source": "src/facade/chart-material-layers.ts",
1903
+ "kind": "type"
1904
+ },
1905
+ {
1906
+ "name": "ChartMaskLayer",
1907
+ "source": "src/facade/chart-material-layers.ts",
1908
+ "kind": "type"
1909
+ },
1910
+ {
1911
+ "name": "ChartMaskPolygon",
1912
+ "source": "src/facade/chart-material-layers.ts",
1913
+ "kind": "type"
1914
+ },
1915
+ {
1916
+ "name": "ChartMaskShape",
1917
+ "source": "src/facade/chart-material-layers.ts",
1918
+ "kind": "type"
1919
+ },
1920
+ {
1921
+ "name": "ChartMaterialLayerScene",
1922
+ "source": "src/facade/chart-material-layers.ts",
1923
+ "kind": "type"
1924
+ },
1875
1925
  {
1876
1926
  "name": "ChartRadianceBatchInput",
1877
1927
  "source": "src/facade/chart-radiance-batch.ts",
@@ -2617,6 +2667,31 @@
2617
2667
  "source": "src/facade/display-view.ts",
2618
2668
  "kind": "type"
2619
2669
  },
2670
+ {
2671
+ "name": "DisplayViewExecution",
2672
+ "source": "src/facade/display-view-gpu.ts",
2673
+ "kind": "type"
2674
+ },
2675
+ {
2676
+ "name": "DisplayViewFastReport",
2677
+ "source": "src/facade/display-view-gpu.ts",
2678
+ "kind": "type"
2679
+ },
2680
+ {
2681
+ "name": "DisplayViewGpuConformance",
2682
+ "source": "src/facade/display-view-gpu.ts",
2683
+ "kind": "type"
2684
+ },
2685
+ {
2686
+ "name": "DisplayViewGpuFallbackReason",
2687
+ "source": "src/facade/display-view-gpu.ts",
2688
+ "kind": "type"
2689
+ },
2690
+ {
2691
+ "name": "DisplayViewGpuMode",
2692
+ "source": "src/facade/display-view-gpu.ts",
2693
+ "kind": "type"
2694
+ },
2620
2695
  {
2621
2696
  "name": "DisplayViewResult",
2622
2697
  "source": "src/facade/simulate-capture.ts",
@@ -3467,6 +3542,11 @@
3467
3542
  "source": "src/optics/psf-foundation.ts",
3468
3543
  "kind": "runtime"
3469
3544
  },
3545
+ {
3546
+ "name": "getWebGpuEnabled",
3547
+ "source": "src/gpu/webgpu-switch.ts",
3548
+ "kind": "runtime"
3549
+ },
3470
3550
  {
3471
3551
  "name": "GlobalSensorReadoutTimingDeclaration",
3472
3552
  "source": "src/sensor/readout-timing.ts",
@@ -3657,6 +3737,11 @@
3657
3737
  "source": "src/gpu/image-kernel-accelerator.ts",
3658
3738
  "kind": "type"
3659
3739
  },
3740
+ {
3741
+ "name": "ImageKernelAdapterDescription",
3742
+ "source": "src/gpu/image-kernel-execution.ts",
3743
+ "kind": "type"
3744
+ },
3660
3745
  {
3661
3746
  "name": "ImageKernelBackend",
3662
3747
  "source": "src/gpu/image-kernel-execution.ts",
@@ -5437,6 +5522,11 @@
5437
5522
  "source": "src/facade/simulate-display-view.ts",
5438
5523
  "kind": "runtime"
5439
5524
  },
5525
+ {
5526
+ "name": "PrepareDisplayViewOptions",
5527
+ "source": "src/facade/display-view-gpu.ts",
5528
+ "kind": "type"
5529
+ },
5440
5530
  {
5441
5531
  "name": "PreparedRgbGamutMapping",
5442
5532
  "source": "src/color/gamut-mapping.ts",
@@ -6227,6 +6317,11 @@
6227
6317
  "source": "src/sensor/capture-mode-timing.ts",
6228
6318
  "kind": "type"
6229
6319
  },
6320
+ {
6321
+ "name": "resolveChartMaterialLayers",
6322
+ "source": "src/facade/chart-material-layers.ts",
6323
+ "kind": "runtime"
6324
+ },
6230
6325
  {
6231
6326
  "name": "resolveChartScene",
6232
6327
  "source": "src/facade/chart-scenes.ts",
@@ -6302,6 +6397,21 @@
6302
6397
  "source": "src/sensor/capture-mode-timing.ts",
6303
6398
  "kind": "type"
6304
6399
  },
6400
+ {
6401
+ "name": "ResolvedChartMaskLayer",
6402
+ "source": "src/facade/chart-material-layers.ts",
6403
+ "kind": "type"
6404
+ },
6405
+ {
6406
+ "name": "ResolvedChartMaskShape",
6407
+ "source": "src/facade/chart-material-layers.ts",
6408
+ "kind": "type"
6409
+ },
6410
+ {
6411
+ "name": "ResolvedChartMaterialLayers",
6412
+ "source": "src/facade/chart-material-layers.ts",
6413
+ "kind": "type"
6414
+ },
6305
6415
  {
6306
6416
  "name": "ResolvedChartScene",
6307
6417
  "source": "src/facade/chart-scenes.ts",
@@ -7947,6 +8057,11 @@
7947
8057
  "source": "src/capture/focus-control.ts",
7948
8058
  "kind": "type"
7949
8059
  },
8060
+ {
8061
+ "name": "setWebGpuEnabled",
8062
+ "source": "src/gpu/webgpu-switch.ts",
8063
+ "kind": "runtime"
8064
+ },
7950
8065
  {
7951
8066
  "name": "ShutterAngleRuleAssessment",
7952
8067
  "source": "src/motion/video-sequence.ts",
@@ -8012,6 +8127,16 @@
8012
8127
  "source": "src/facade/simulate-capture.ts",
8013
8128
  "kind": "type"
8014
8129
  },
8130
+ {
8131
+ "name": "SimulateCaptureAutoIsoAfterMaximum",
8132
+ "source": "src/facade/simulate-capture.ts",
8133
+ "kind": "type"
8134
+ },
8135
+ {
8136
+ "name": "SimulateCaptureAutoIsoReport",
8137
+ "source": "src/facade/simulate-capture.ts",
8138
+ "kind": "type"
8139
+ },
8015
8140
  {
8016
8141
  "name": "SimulateCaptureBorderHandling",
8017
8142
  "source": "src/facade/simulate-capture.ts",
@@ -0,0 +1,137 @@
1
+ # facade/chart-material-layers.ts public contracts
2
+
3
+ The package and root API versions are recorded once in [Navigation](../API_REFERENCE.md) · [Developer guide](https://github.com/Photivra/photivra/blob/main/docs/DEVELOPERS.md). Generated signatures retain independent schema/model versions. Only the exports listed here are root-package contracts; module-local helpers are not supported deep imports.
4
+
5
+ ## CHART_MASK_INDEX_GRAIN
6
+
7
+ The cell index grain of every layer: cells across and down the mask box.
8
+
9
+ ```ts
10
+ CHART_MASK_INDEX_GRAIN = Object.freeze({ cellsX: 64, cellsY: 16 })
11
+ ```
12
+
13
+ ## CHART_MATERIAL_LAYER_LIMITS
14
+
15
+ Limits of a declared scene.
16
+
17
+ ```ts
18
+ CHART_MATERIAL_LAYER_LIMITS = Object.freeze({ maximumLayers: 16, maximumShapes: 4096, maximumRings: 256, maximumEdges: 65_536 })
19
+ ```
20
+
21
+ ## ChartMaskAnnulus
22
+
23
+ A stroked circle: the points at distance innerRadius ≤ d ≤ outerRadius from the centre, mask units.
24
+
25
+ ```ts
26
+ export interface ChartMaskAnnulus { kind: "annulus"; centerX: number; centerY: number; innerRadius: number; outerRadius: number }
27
+ ```
28
+
29
+ ## ChartMaskLayer
30
+
31
+ A shape mask printed over the chart: its box [0, unitsWidth] × [0, unitsHeight] (y down) fills `rectangle` (frame units, v up).
32
+
33
+ ```ts
34
+ export interface ChartMaskLayer {
35
+ kind: "shape-mask";
36
+ rectangle: { u0: number; v0: number; u1: number; v1: number };
37
+ unitsWidth: number;
38
+ unitsHeight: number;
39
+ /** 1 to 4096 shapes, in order; the ink material where any contains the point. */
40
+ shapes: readonly ChartMaskShape[];
41
+ backgroundReflectance: ChartReflectance;
42
+ inkReflectance: ChartReflectance;
43
+ }
44
+ ```
45
+
46
+ ## ChartMaskPolygon
47
+
48
+ A filled polygon: rings as flat [x0, y0, x1, y1, …] in mask units (y down), non-zero winding over all rings.
49
+
50
+ ```ts
51
+ export interface ChartMaskPolygon { kind: "polygon"; rings: readonly (readonly number[])[] }
52
+ ```
53
+
54
+ ## ChartMaskShape
55
+
56
+ The exact contract is declared below; use the domain guide for assumptions and staged integration.
57
+
58
+ ```ts
59
+ export type ChartMaskShape = ChartMaskPolygon | ChartMaskAnnulus;
60
+ ```
61
+
62
+ ## ChartMaterialLayerScene
63
+
64
+ A chart under 1 to 16 shape-mask layers, as data; `resolveChartMaterialLayers` evaluates it.
65
+
66
+ ```ts
67
+ export interface ChartMaterialLayerScene { kind: "material-layers"; sceneId: string; chart: ChartScene; layers: readonly ChartMaskLayer[] }
68
+ ```
69
+
70
+ ## resolveChartMaterialLayers
71
+
72
+ Validates a declared material scene and resolves its chart (in a frame of `aspect` = height / width) and its
73
+ layers. `materialAt` is the float64 reference the GPU stage is checked against, and `callerScene` is the same
74
+ scene for `simulateCapture`'s `scene` option.
75
+
76
+ ```ts
77
+ export function resolveChartMaterialLayers(input: { scene: ChartMaterialLayerScene; aspect: number }): ResolvedChartMaterialLayers;
78
+ ```
79
+
80
+ This call is synchronous; any supplied provider must follow its explicit synchronous contract.
81
+
82
+ ## ResolvedChartMaskLayer
83
+
84
+ The exact contract is declared below; use the domain guide for assumptions and staged integration.
85
+
86
+ ```ts
87
+ export interface ResolvedChartMaskLayer {
88
+ rectangle: { u0: number; v0: number; u1: number; v1: number };
89
+ unitsWidth: number;
90
+ unitsHeight: number;
91
+ /** Mask units per frame unit: unitsWidth / (u1 − u0) and unitsHeight / (v1 − v0). */
92
+ scaleX: number;
93
+ scaleY: number;
94
+ shapes: readonly ResolvedChartMaskShape[];
95
+ cellsX: number;
96
+ cellsY: number;
97
+ cellWidth: number;
98
+ cellHeight: number;
99
+ /** Per cell (row by row), the shape indices whose bounding box meets the cell grown by one cell. */
100
+ cells: readonly Uint32Array[];
101
+ backgroundMaterial: number;
102
+ inkMaterial: number;
103
+ /** Whether a point in mask units is ink (through the cell index). */
104
+ containsUnits(x: number, y: number): boolean;
105
+ }
106
+ ```
107
+
108
+ ## ResolvedChartMaskShape
109
+
110
+ Internal: a shape with its bounding box and flattened edges (polygon) or squared radii (annulus).
111
+
112
+ ```ts
113
+ export type ResolvedChartMaskShape =
114
+ | { kind: "polygon"; box: readonly [number, number, number, number]; edges: Float64Array }
115
+ | { kind: "annulus"; box: readonly [number, number, number, number]; centerX: number; centerY: number; inner2: number; outer2: number };
116
+ ```
117
+
118
+ ## ResolvedChartMaterialLayers
119
+
120
+ The exact contract is declared below; use the domain guide for assumptions and staged integration.
121
+
122
+ ```ts
123
+ export interface ResolvedChartMaterialLayers {
124
+ kind: "material-layers";
125
+ sceneId: string;
126
+ /** The chart under the layers; its materials come first in `materials`. */
127
+ chart: ResolvedChartScene;
128
+ layers: readonly ResolvedChartMaskLayer[];
129
+ materials: ResolvedChartScene["materials"];
130
+ /** Internal: the caller input behind each material (undefined for an engine neutral), for the scene digest. */
131
+ materialInputs: readonly unknown[];
132
+ /** Material index at a frame point (u right, v up): the topmost layer whose rectangle holds the point, else the chart. */
133
+ materialAt(u: number, v: number): number;
134
+ /** The same scene as a caller material scene for `simulateCapture` and the display view (chart-local coordinates when the chart has a size). */
135
+ callerScene: CallerMaterialScene;
136
+ }
137
+ ```
@@ -46,8 +46,8 @@ The exact contract is declared below; use the domain guide for assumptions and s
46
46
  ```ts
47
47
  export interface ChartRadianceBatchInput {
48
48
  schemaVersion: typeof CHART_RADIANCE_BATCH_SCHEMA_VERSION;
49
- /** An engine chart preset (caller scene functions are not supported here). */
50
- scene: ChartScene;
49
+ /** An engine chart preset, or (#477) a declared `material-layers` scene: a chart under shape-mask layers. Caller scene functions are not supported here. */
50
+ scene: ChartScene | ChartMaterialLayerScene;
51
51
  illuminant: CaptureIlluminant;
52
52
  illuminanceLux: number;
53
53
  /** Frame height / width. */
@@ -74,7 +74,12 @@ Validated plan with the resolved chart, illuminant and irradiance scale. Arrays
74
74
 
75
75
  ```ts
76
76
  export interface ChartRadianceBatchPlan {
77
+ /** The resolved chart; with a `material-layers` scene, the chart under the layers. */
77
78
  chart: ResolvedChartScene;
79
+ /** The resolved layers of a `material-layers` scene, or null for a chart preset. */
80
+ layers: ResolvedChartMaterialLayers | null;
81
+ /** Every material a query can resolve to: the chart's, then each layer's background and ink. */
82
+ materials: ResolvedChartScene["materials"];
78
83
  illuminant: ResolvedCaptureIlluminant;
79
84
  irradianceScale: number;
80
85
  queryCount: number;
@@ -0,0 +1,94 @@
1
+ # facade/display-view-gpu.ts public contracts
2
+
3
+ The package and root API versions are recorded once in [Navigation](../API_REFERENCE.md) · [Developer guide](https://github.com/Photivra/photivra/blob/main/docs/DEVELOPERS.md). Generated signatures retain independent schema/model versions. Only the exports listed here are root-package contracts; module-local helpers are not supported deep imports.
4
+
5
+ ## DisplayViewExecution
6
+
7
+ 2.11 (#481): where a display view's render ran, in the words of the image-kernel execution record (`ImageKernelExecution`):
8
+ `backend` names the path that ran (`cpu-reference`, the float64 engine reference, or `webgpu-f32`, a float32 approximation
9
+ within `errorBound`), `requestedBackend` what `gpu` asked for, and `fallbackReason` why a request for the GPU ran the CPU.
10
+ `adapter` describes the device's adapter whenever one was involved, also when the view then fell back; `conformance` is
11
+ the device's self-check once it has run. A CPU render keeps `assurance: "engine-reference"` and `fast: false`.
12
+
13
+ ```ts
14
+ export interface DisplayViewExecution extends Omit<ImageKernelExecution, "fallbackReason"> {
15
+ /** The `gpu` option the view was prepared with. */
16
+ gpu: DisplayViewGpuMode;
17
+ fallbackReason: DisplayViewGpuFallbackReason | null;
18
+ adapter: ImageKernelAdapterDescription | null;
19
+ conformance: DisplayViewGpuConformance | null;
20
+ /**
21
+ * 2.11: the composite chart kernel's device probe when this render needed it (composite charts, the 2.3 elements and
22
+ * `material-layers` scenes): the device class and the product path the kernel ran with, or, on a refusal (`fallbackReason`
23
+ * `unsupported-on-backend`), why. Null when the render did not run the probe (the 2.0 presets, `gpu: "off"`).
24
+ */
25
+ compositeProbe: ChartCompositeProbeRecord | null;
26
+ }
27
+ ```
28
+
29
+ ## DisplayViewFastReport
30
+
31
+ 2.11 (#481): `diagnostics.fast` of a display view: the capture's report plus where the render ran.
32
+
33
+ ```ts
34
+ export interface DisplayViewFastReport extends SimulateCaptureFastReport {
35
+ /** Where this render ran (see {@link DisplayViewExecution}). `assurance` above follows it. */
36
+ execution: DisplayViewExecution;
37
+ }
38
+ ```
39
+
40
+ ## DisplayViewGpuConformance
41
+
42
+ 2.11 (#481): the run-time conformance self-check of a device, run once before the view's first GPU render.
43
+
44
+ ```ts
45
+ export interface DisplayViewGpuConformance {
46
+ /** The ids of the cases run, in order (the built-in image-kernel cases, then the renderer's own). */
47
+ cases: readonly string[];
48
+ passed: boolean;
49
+ /** The first case that failed, or null. */
50
+ failedCase: string | null;
51
+ /** What the failed case reported, or null. */
52
+ detail: string | null;
53
+ }
54
+ ```
55
+
56
+ ## DisplayViewGpuFallbackReason
57
+
58
+ 2.11 (#481): why a display view that asked for the GPU (`gpu: "auto"`) ran the CPU reference. The accelerator's acquisition
59
+ reasons, plus: `unsupported-on-backend` (no GPU display-view renderer exists in this version, or it does not support the
60
+ request), `conformance-failed` (the device failed the run-time self-check before the view's first GPU render), `device-lost`
61
+ (the device was lost; the rest of the view runs on the CPU) and `disposed` (the prepared view was disposed).
62
+
63
+ ```ts
64
+ export type DisplayViewGpuFallbackReason = ImageKernelFallbackReason | "unsupported-on-backend" | "conformance-failed" | "device-lost" | "disposed";
65
+ ```
66
+
67
+ ## DisplayViewGpuMode
68
+
69
+ 2.11 (#481): whether a prepared display view may render on the GPU. `"off"` (the default) is the CPU reference, today's
70
+ behaviour byte for byte. `"auto"` renders on WebGPU when a conforming device is available and the request is supported, and
71
+ otherwise runs the CPU reference and says why. `"require"` fails instead of falling back. In the accelerator's words: `"auto"`
72
+ is `backend: "webgpu-f32"` with `fallback: "cpu-reference"`, `"require"` is `fallback: "fail"`, `"off"` is `backend: "cpu-reference"`.
73
+
74
+ ```ts
75
+ export type DisplayViewGpuMode = "off" | "auto" | "require";
76
+ ```
77
+
78
+ ## PrepareDisplayViewOptions
79
+
80
+ 2.11 (#481): the second argument of `prepareDisplayView`.
81
+
82
+ ```ts
83
+ export interface PrepareDisplayViewOptions {
84
+ /** See {@link DisplayViewGpuMode}. Default `"off"`. */
85
+ gpu?: DisplayViewGpuMode;
86
+ /**
87
+ * Where the device comes from, with `gpu: "auto"` or `"require"`: a WebGPU entry point (a worker's `navigator.gpu`), or an
88
+ * `ImageKernelAccelerator` whose device the view shares (the accelerator keeps ownership; `dispose()` of the prepared view
89
+ * leaves it alone). Without it the engine acquires a device from `globalThis.navigator.gpu` and owns it until `dispose()`.
90
+ * Refused with `gpu: "off"`.
91
+ */
92
+ gpuDevice?: unknown;
93
+ }
94
+ ```
@@ -82,7 +82,8 @@ export interface ChartSizeOption {
82
82
 
83
83
  ## createPlanarSceneRadianceProvider
84
84
 
85
- Public scene-preset provider. Places an engine chart (or a caller reflectance or radiance function) on
85
+ Public scene-preset provider. Places an engine chart (or a declared `material-layers` scene, #491, evaluated as
86
+ its `callerScene`; or a caller reflectance, radiance or material function) on
86
87
  a plane `distanceM` in front of the camera and `framedWidthM` wide (frame units u = ±1 at its edges),
87
88
  lit by `illuminant` at `illuminanceLux`. The returned `evaluateRadiance` and `evaluateApertureRadiance`
88
89
  follow the native environment RAW provider contract. They answer requests for scene `sceneId` and
@@ -90,7 +91,7 @@ provider `providerProfileId`.
90
91
 
91
92
  ```ts
92
93
  export function createPlanarSceneRadianceProvider(input: {
93
- scene: ChartScene | CallerReflectanceScene | CallerRadianceScene | CallerMaterialScene;
94
+ scene: ChartScene | ChartMaterialLayerScene | CallerReflectanceScene | CallerRadianceScene | CallerMaterialScene;
94
95
  illuminant: CaptureIlluminant;
95
96
  illuminanceLux: number;
96
97
  distanceM: number;