@photivra/engine 2.9.0 → 2.11.1

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 (147) hide show
  1. package/CHANGELOG.md +223 -1
  2. package/CITATION.cff +1 -1
  3. package/NODE_SUPPORT.md +21 -3
  4. package/README.md +6 -6
  5. package/SECURITY.md +1 -1
  6. package/THIRD_PARTY.md +2 -0
  7. package/dist/capture/native-environment-lean.js +89 -5
  8. package/dist/capture/native-environment-lean.js.map +1 -1
  9. package/dist/capture/native-environment-tabulated.d.ts +37 -0
  10. package/dist/capture/native-environment-tabulated.js +42 -6
  11. package/dist/capture/native-environment-tabulated.js.map +1 -1
  12. package/dist/core/portable-math.d.ts +19 -0
  13. package/dist/core/portable-math.js +82 -0
  14. package/dist/core/portable-math.js.map +1 -1
  15. package/dist/core/version.d.ts +1 -1
  16. package/dist/core/version.js +1 -1
  17. package/dist/core/version.js.map +1 -1
  18. package/dist/facade/channel-response.d.ts +15 -0
  19. package/dist/facade/channel-response.js +33 -0
  20. package/dist/facade/channel-response.js.map +1 -0
  21. package/dist/facade/chart-material-layers.d.ts +115 -0
  22. package/dist/facade/chart-material-layers.js +224 -0
  23. package/dist/facade/chart-material-layers.js.map +1 -0
  24. package/dist/facade/chart-radiance-batch.d.ts +8 -2
  25. package/dist/facade/chart-radiance-batch.js +11 -4
  26. package/dist/facade/chart-radiance-batch.js.map +1 -1
  27. package/dist/facade/chart-scenes.d.ts +134 -0
  28. package/dist/facade/chart-scenes.js +32 -22
  29. package/dist/facade/chart-scenes.js.map +1 -1
  30. package/dist/facade/diffraction-provider.d.ts +8 -2
  31. package/dist/facade/diffraction-provider.js +120 -16
  32. package/dist/facade/diffraction-provider.js.map +1 -1
  33. package/dist/facade/display-view-gpu-session.d.ts +18 -0
  34. package/dist/facade/display-view-gpu-session.js +280 -0
  35. package/dist/facade/display-view-gpu-session.js.map +1 -0
  36. package/dist/facade/display-view-gpu.d.ts +146 -0
  37. package/dist/facade/display-view-gpu.js +59 -0
  38. package/dist/facade/display-view-gpu.js.map +1 -0
  39. package/dist/facade/display-view.d.ts +123 -1
  40. package/dist/facade/display-view.js +478 -116
  41. package/dist/facade/display-view.js.map +1 -1
  42. package/dist/facade/expected-signal-setup.d.ts +5 -0
  43. package/dist/facade/expected-signal-setup.js +18 -1
  44. package/dist/facade/expected-signal-setup.js.map +1 -1
  45. package/dist/facade/expected-signal.d.ts +80 -6
  46. package/dist/facade/expected-signal.js +200 -24
  47. package/dist/facade/expected-signal.js.map +1 -1
  48. package/dist/facade/scene-radiance.d.ts +4 -2
  49. package/dist/facade/scene-radiance.js +7 -4
  50. package/dist/facade/scene-radiance.js.map +1 -1
  51. package/dist/facade/simulate-capture.d.ts +81 -7
  52. package/dist/facade/simulate-capture.js +276 -53
  53. package/dist/facade/simulate-capture.js.map +1 -1
  54. package/dist/facade/simulate-display-view.d.ts +54 -3
  55. package/dist/facade/simulate-display-view.js +120 -27
  56. package/dist/facade/simulate-display-view.js.map +1 -1
  57. package/dist/gpu/chart-composite-gpu.d.ts +119 -0
  58. package/dist/gpu/chart-composite-gpu.js +572 -0
  59. package/dist/gpu/chart-composite-gpu.js.map +1 -0
  60. package/dist/gpu/chart-radiance-gpu.d.ts +6 -6
  61. package/dist/gpu/chart-radiance-gpu.js +9 -11
  62. package/dist/gpu/chart-radiance-gpu.js.map +1 -1
  63. package/dist/gpu/display-view-chart-material-module.d.ts +10 -0
  64. package/dist/gpu/display-view-chart-material-module.js +58 -0
  65. package/dist/gpu/display-view-chart-material-module.js.map +1 -0
  66. package/dist/gpu/display-view-composite-material-module.d.ts +68 -0
  67. package/dist/gpu/display-view-composite-material-module.js +248 -0
  68. package/dist/gpu/display-view-composite-material-module.js.map +1 -0
  69. package/dist/gpu/display-view-quality-gpu.d.ts +185 -0
  70. package/dist/gpu/display-view-quality-gpu.js +1000 -0
  71. package/dist/gpu/display-view-quality-gpu.js.map +1 -0
  72. package/dist/gpu/display-view-speed-gpu.d.ts +156 -0
  73. package/dist/gpu/display-view-speed-gpu.js +524 -0
  74. package/dist/gpu/display-view-speed-gpu.js.map +1 -0
  75. package/dist/gpu/image-kernel-accelerator.d.ts +23 -4
  76. package/dist/gpu/image-kernel-accelerator.js +58 -10
  77. package/dist/gpu/image-kernel-accelerator.js.map +1 -1
  78. package/dist/gpu/image-kernel-execution.d.ts +60 -3
  79. package/dist/gpu/image-kernel-execution.js +2 -2
  80. package/dist/gpu/image-kernel-execution.js.map +1 -1
  81. package/dist/gpu/sensor-stage-gpu.d.ts +11 -0
  82. package/dist/gpu/sensor-stage-gpu.js +42 -13
  83. package/dist/gpu/sensor-stage-gpu.js.map +1 -1
  84. package/dist/gpu/webgpu-runtime.d.ts +4 -2
  85. package/dist/gpu/webgpu-runtime.js +13 -4
  86. package/dist/gpu/webgpu-runtime.js.map +1 -1
  87. package/dist/gpu/webgpu-switch.d.ts +4 -0
  88. package/dist/gpu/webgpu-switch.js +29 -0
  89. package/dist/gpu/webgpu-switch.js.map +1 -0
  90. package/dist/gpu/wgsl-chart-composite-kernel.d.ts +52 -0
  91. package/dist/gpu/wgsl-chart-composite-kernel.js +515 -0
  92. package/dist/gpu/wgsl-chart-composite-kernel.js.map +1 -0
  93. package/dist/gpu/wgsl-chart-kernel.d.ts +11 -9
  94. package/dist/gpu/wgsl-chart-kernel.js +33 -27
  95. package/dist/gpu/wgsl-chart-kernel.js.map +1 -1
  96. package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +95 -0
  97. package/dist/gpu/wgsl-display-view-quality-kernel.js +769 -0
  98. package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -0
  99. package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +75 -0
  100. package/dist/gpu/wgsl-display-view-speed-kernel.js +386 -0
  101. package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -0
  102. package/dist/gpu/wgsl-sensor-kernel.d.ts +28 -9
  103. package/dist/gpu/wgsl-sensor-kernel.js +94 -50
  104. package/dist/gpu/wgsl-sensor-kernel.js.map +1 -1
  105. package/dist/index.d.ts +6 -3
  106. package/dist/index.js +4 -2
  107. package/dist/index.js.map +1 -1
  108. package/dist/optics/defocus-disc-kernel.d.ts +61 -0
  109. package/dist/optics/defocus-disc-kernel.js +191 -0
  110. package/dist/optics/defocus-disc-kernel.js.map +1 -0
  111. package/dist/optics/irradiance-convolution.d.ts +11 -0
  112. package/dist/optics/irradiance-convolution.js +64 -24
  113. package/dist/optics/irradiance-convolution.js.map +1 -1
  114. package/dist/optics/scene-to-sensor-irradiance.d.ts +13 -0
  115. package/dist/optics/scene-to-sensor-irradiance.js +58 -24
  116. package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
  117. package/dist/optics/sensor-aperture-rays.js +2 -1
  118. package/dist/optics/sensor-aperture-rays.js.map +1 -1
  119. package/dist/optics/sensor-environment-query.js +4 -3
  120. package/dist/optics/sensor-environment-query.js.map +1 -1
  121. package/dist/optics/site-diffraction-kernel.d.ts +16 -0
  122. package/dist/optics/site-diffraction-kernel.js +60 -8
  123. package/dist/optics/site-diffraction-kernel.js.map +1 -1
  124. package/dist/processing/demosaic.js +114 -37
  125. package/dist/processing/demosaic.js.map +1 -1
  126. package/dist/schema/scene-radiance.d.ts +8 -0
  127. package/dist/schema/scene-radiance.js +28 -17
  128. package/dist/schema/scene-radiance.js.map +1 -1
  129. package/dist/sensor/environment-photo-signal.d.ts +21 -0
  130. package/dist/sensor/environment-photo-signal.js +68 -2
  131. package/dist/sensor/environment-photo-signal.js.map +1 -1
  132. package/docs/API_REFERENCE.md +60 -1
  133. package/docs/QUICK_START.md +120 -11
  134. package/docs/USAGE.md +82 -2
  135. package/docs/api/core-version.md +1 -1
  136. package/docs/api/exports.json +157 -2
  137. package/docs/api/facade-chart-material-layers.md +137 -0
  138. package/docs/api/facade-chart-radiance-batch.md +7 -2
  139. package/docs/api/facade-display-view-gpu.md +94 -0
  140. package/docs/api/facade-display-view.md +50 -0
  141. package/docs/api/facade-scene-radiance.md +3 -2
  142. package/docs/api/facade-simulate-capture.md +81 -12
  143. package/docs/api/facade-simulate-display-view.md +39 -2
  144. package/docs/api/gpu-image-kernel-accelerator.md +10 -3
  145. package/docs/api/gpu-image-kernel-execution.md +76 -4
  146. package/docs/api/gpu-webgpu-switch.md +23 -0
  147. 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:
@@ -7516,6 +7526,57 @@ const view = await simulateDisplayView({ scene: { preset: "slanted-edge" }, sens
7516
7526
  console.log(view.kind, view.view.scaleX, view.assumptions.find((a) => a.id === "view.definition")?.value);
7517
7527
  ```
7518
7528
 
7529
+ #### Rendering a prepared view on the GPU (2.11, #481)
7530
+
7531
+ `prepareDisplayView(request, { gpu })` chooses the renderer: `"off"` (the default) is the CPU reference, `"auto"` the GPU
7532
+ when a conforming device is available and the request is supported (else the CPU, labelled), `"require"` fails instead of
7533
+ falling back. `gpuDevice` hands the view a worker's `navigator.gpu` or an `ImageKernelAccelerator` whose device it shares.
7534
+ Every render says which path ran in `diagnostics.fast.execution`, in the accelerator's words. No GPU display-view renderer
7535
+ exists yet (#478), so today `"auto"` runs the CPU reference labelled `unsupported-on-backend` without requesting a device;
7536
+ see [Rendering on the GPU](https://github.com/Photivra/photivra/blob/main/docs/DISPLAY_VIEW.md#rendering-on-the-gpu).
7537
+
7538
+ ```ts
7539
+ import { prepareDisplayView, type SimulateCaptureOptions } from "@photivra/engine";
7540
+
7541
+ const request: SimulateCaptureOptions = { scene: { preset: "siemens-star" }, sensor: { pixelPitchMicrometers: 4 }, output: { width: 600, height: 400 } };
7542
+ const prepared = await prepareDisplayView(request, { gpu: "auto" }); // acquisition failures fall back; with "require" they throw here
7543
+ const tile = await prepared.render({ width: 300, height: 200, region: { x: 120, y: 80, width: 32, height: 32 } });
7544
+ const ran = tile.diagnostics.fast.execution;
7545
+ // "cpu-reference" when the reference ran (and why), "webgpu-f32" with its bound and adapter when the GPU did.
7546
+ console.log(ran.backend, ran.fallbackReason, ran.assurance, ran.errorBound, ran.adapter, tile.diagnostics.fast.assurance);
7547
+ prepared.dispose(); // releases a device the view acquired; a shared accelerator's device stays its owner's
7548
+ ```
7549
+
7550
+ #### Sharing AHD correction states between workers
7551
+
7552
+ With `output.demosaic: "ahd"`, low-signal display pixels read correction states that each realm (a page, a Web Worker)
7553
+ computes and keeps for itself. Two workers can split a part's states and exchange them instead of both computing all
7554
+ of them; the renders have the same bytes either way (see "AHD at low signal" in
7555
+ [DISPLAY_VIEW.md](https://github.com/Photivra/photivra/blob/main/docs/DISPLAY_VIEW.md#ahd-at-low-signal)). Import only
7556
+ states whose key a prepared view reported. The two handles below run in one script for the example; in an app each
7557
+ runs in its own worker, and the arrays travel with `postMessage(set, [set.gridKeys.buffer, set.values.buffer])`.
7558
+
7559
+ ```ts
7560
+ import { serializeDisplayViewCorrectionStates, bindDisplayViewCorrectionStates, prepareDisplayView, type SimulateCaptureOptions } from "@photivra/engine";
7561
+
7562
+ const request: SimulateCaptureOptions = { scene: { preset: "uniform", reflectance: 0.18 }, exposure: { iso: 1600, shutterSeconds: 1 / 2000 },
7563
+ sensor: { pixelPitchMicrometers: 1.4 }, output: { width: 200, height: 150, demosaic: "ahd" } };
7564
+ const part = { width: 20, height: 15, region: { x: 0, y: 0, width: 10, height: 8 } };
7565
+ // Each worker prepares the same request; the key says which states it reads.
7566
+ const workerA = await prepareDisplayView(request), workerB = await prepareDisplayView(request);
7567
+ console.log(workerA.correctionKey() === workerB.correctionKey());
7568
+ // Worker A finds the states the part needs (no image, no state computed) and gives half to each worker.
7569
+ const { gridKeys } = await workerA.collectCorrectionStates(part);
7570
+ const half = Math.ceil(gridKeys.length / 2);
7571
+ const fromA = await workerA.computeCorrectionStates(gridKeys.slice(0, half));
7572
+ const fromB = await workerB.computeCorrectionStates(gridKeys.slice(half));
7573
+ // Each worker imports the other's share (in one realm, as here, the second import adds nothing new).
7574
+ console.log(bindDisplayViewCorrectionStates([fromB]), bindDisplayViewCorrectionStates([fromA]));
7575
+ // Either worker now renders the part without computing a state; a new worker can start from an export.
7576
+ const view = await workerA.render(part);
7577
+ console.log(view.diagnostics.ahdCorrectedPixelCount, serializeDisplayViewCorrectionStates().map((set) => set.gridKeys.length));
7578
+ ```
7579
+
7519
7580
  ### Facade 2.0 options: output, demosaic, optics and motion
7520
7581
 
7521
7582
  Each 2.0 option is opt-in and uses an existing public contract. Without them, the facade's output is
@@ -7562,6 +7623,25 @@ const barrel = await simulateCapture({
7562
7623
  console.log(barrel.request.siteInput(0).environment.lensFieldMapping?.distortion.kind);
7563
7624
  ```
7564
7625
 
7626
+ `lens.defocus: { model: "geometric-disc" }` (#492) renders defocus of the flat scene plane when
7627
+ `lens.focusDistanceM` differs from `subjectDistanceM`. The thin-lens blur circle becomes a uniform disc on the site
7628
+ lattice, and the capture convolves the scene radiance with it, which is a geometric approximation. With
7629
+ `lens.diffraction`, each spectral node's diffraction kernel is convolved with the disc, which is a further
7630
+ approximation. The `lens.defocus` assumption records the diameter in µm and in sites, the kernel radius and the
7631
+ execution. `simulateDisplayView` does not render it yet. See [Optics](QUICK_START.md#optics).
7632
+
7633
+ ```ts
7634
+ import { simulateCapture } from "@photivra/engine";
7635
+
7636
+ const blurred = await simulateCapture({
7637
+ scene: { preset: "slanted-edge" },
7638
+ subjectDistanceM: 2,
7639
+ lens: { focalLengthMm: 50, fNumber: 4, focusDistanceM: 1.8, defocus: { model: "geometric-disc" } },
7640
+ output: { width: 16, height: 12 }
7641
+ });
7642
+ console.log(blurred.assumptions.find((a) => a.id === "lens.defocus")?.value); // diameterSites ≈ 5.95, kernelRadiusSites 3
7643
+ ```
7644
+
7565
7645
  `motion.angularVelocityRadPerSec` rotates the camera during the exposure (8 time midpoints by
7566
7646
  default). `motion.shutter: "rolling"` derives each site's exposure window from the body's rolling
7567
7647
  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.9.0" as const
14
+ ENGINE_API_VERSION = "2.11.1" as const
15
15
  ```
@@ -1,6 +1,6 @@
1
1
  {
2
- "packageVersion": "2.9.0",
3
- "engineApiVersion": "2.9.0",
2
+ "packageVersion": "2.11.1",
3
+ "engineApiVersion": "2.11.1",
4
4
  "exports": [
5
5
  {
6
6
  "name": "AbsoluteUncertaintyEstimate",
@@ -212,6 +212,11 @@
212
212
  "source": "src/processing/denoise.ts",
213
213
  "kind": "type"
214
214
  },
215
+ {
216
+ "name": "bindDisplayViewCorrectionStates",
217
+ "source": "src/facade/display-view.ts",
218
+ "kind": "runtime"
219
+ },
215
220
  {
216
221
  "name": "bindIsoCapabilityToExposureCapabilities",
217
222
  "source": "src/equipment/iso-capabilities.ts",
@@ -1822,6 +1827,16 @@
1822
1827
  "source": "src/facade/chart-scenes.ts",
1823
1828
  "kind": "runtime"
1824
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
+ },
1825
1840
  {
1826
1841
  "name": "CHART_RADIANCE_BATCH_LIMITS",
1827
1842
  "source": "src/facade/chart-radiance-batch.ts",
@@ -1857,6 +1872,21 @@
1857
1872
  "source": "src/facade/chart-scenes.ts",
1858
1873
  "kind": "type"
1859
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
+ },
1860
1890
  {
1861
1891
  "name": "ChartElementScene",
1862
1892
  "source": "src/facade/chart-scenes.ts",
@@ -1867,6 +1897,31 @@
1867
1897
  "source": "src/facade/subject-framing.ts",
1868
1898
  "kind": "type"
1869
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
+ },
1870
1925
  {
1871
1926
  "name": "ChartRadianceBatchInput",
1872
1927
  "source": "src/facade/chart-radiance-batch.ts",
@@ -2602,6 +2657,41 @@
2602
2657
  "source": "src/core/spectral-composition.ts",
2603
2658
  "kind": "type"
2604
2659
  },
2660
+ {
2661
+ "name": "DisplayViewCorrectionStateKeys",
2662
+ "source": "src/facade/display-view.ts",
2663
+ "kind": "type"
2664
+ },
2665
+ {
2666
+ "name": "DisplayViewCorrectionStateSet",
2667
+ "source": "src/facade/display-view.ts",
2668
+ "kind": "type"
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
+ },
2605
2695
  {
2606
2696
  "name": "DisplayViewResult",
2607
2697
  "source": "src/facade/simulate-capture.ts",
@@ -3452,6 +3542,11 @@
3452
3542
  "source": "src/optics/psf-foundation.ts",
3453
3543
  "kind": "runtime"
3454
3544
  },
3545
+ {
3546
+ "name": "getWebGpuEnabled",
3547
+ "source": "src/gpu/webgpu-switch.ts",
3548
+ "kind": "runtime"
3549
+ },
3455
3550
  {
3456
3551
  "name": "GlobalSensorReadoutTimingDeclaration",
3457
3552
  "source": "src/sensor/readout-timing.ts",
@@ -3642,6 +3737,11 @@
3642
3737
  "source": "src/gpu/image-kernel-accelerator.ts",
3643
3738
  "kind": "type"
3644
3739
  },
3740
+ {
3741
+ "name": "ImageKernelAdapterDescription",
3742
+ "source": "src/gpu/image-kernel-execution.ts",
3743
+ "kind": "type"
3744
+ },
3645
3745
  {
3646
3746
  "name": "ImageKernelBackend",
3647
3747
  "source": "src/gpu/image-kernel-execution.ts",
@@ -5422,6 +5522,11 @@
5422
5522
  "source": "src/facade/simulate-display-view.ts",
5423
5523
  "kind": "runtime"
5424
5524
  },
5525
+ {
5526
+ "name": "PrepareDisplayViewOptions",
5527
+ "source": "src/facade/display-view-gpu.ts",
5528
+ "kind": "type"
5529
+ },
5425
5530
  {
5426
5531
  "name": "PreparedRgbGamutMapping",
5427
5532
  "source": "src/color/gamut-mapping.ts",
@@ -6212,6 +6317,11 @@
6212
6317
  "source": "src/sensor/capture-mode-timing.ts",
6213
6318
  "kind": "type"
6214
6319
  },
6320
+ {
6321
+ "name": "resolveChartMaterialLayers",
6322
+ "source": "src/facade/chart-material-layers.ts",
6323
+ "kind": "runtime"
6324
+ },
6215
6325
  {
6216
6326
  "name": "resolveChartScene",
6217
6327
  "source": "src/facade/chart-scenes.ts",
@@ -6287,6 +6397,21 @@
6287
6397
  "source": "src/sensor/capture-mode-timing.ts",
6288
6398
  "kind": "type"
6289
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
+ },
6290
6415
  {
6291
6416
  "name": "ResolvedChartScene",
6292
6417
  "source": "src/facade/chart-scenes.ts",
@@ -7867,6 +7992,11 @@
7867
7992
  "source": "src/sensor/dark-current.ts",
7868
7993
  "kind": "type"
7869
7994
  },
7995
+ {
7996
+ "name": "serializeDisplayViewCorrectionStates",
7997
+ "source": "src/facade/display-view.ts",
7998
+ "kind": "runtime"
7999
+ },
7870
8000
  {
7871
8001
  "name": "serializeNativeRawDng",
7872
8002
  "source": "src/capture/native-raw-dng.ts",
@@ -7927,6 +8057,11 @@
7927
8057
  "source": "src/capture/focus-control.ts",
7928
8058
  "kind": "type"
7929
8059
  },
8060
+ {
8061
+ "name": "setWebGpuEnabled",
8062
+ "source": "src/gpu/webgpu-switch.ts",
8063
+ "kind": "runtime"
8064
+ },
7930
8065
  {
7931
8066
  "name": "ShutterAngleRuleAssessment",
7932
8067
  "source": "src/motion/video-sequence.ts",
@@ -7972,6 +8107,11 @@
7972
8107
  "source": "src/facade/simulate-capture.ts",
7973
8108
  "kind": "runtime"
7974
8109
  },
8110
+ {
8111
+ "name": "SIMULATE_CAPTURE_FAST_OPTIONS",
8112
+ "source": "src/facade/simulate-capture.ts",
8113
+ "kind": "runtime"
8114
+ },
7975
8115
  {
7976
8116
  "name": "SIMULATE_DISPLAY_VIEW_DEFAULT_SAMPLES_PER_AXIS",
7977
8117
  "source": "src/facade/simulate-capture.ts",
@@ -8007,6 +8147,11 @@
8007
8147
  "source": "src/facade/simulate-capture.ts",
8008
8148
  "kind": "type"
8009
8149
  },
8150
+ {
8151
+ "name": "SimulateCaptureDemosaicRecord",
8152
+ "source": "src/facade/simulate-capture.ts",
8153
+ "kind": "type"
8154
+ },
8010
8155
  {
8011
8156
  "name": "SimulateCaptureDngPart",
8012
8157
  "source": "src/facade/simulate-capture.ts",
@@ -8017,6 +8162,16 @@
8017
8162
  "source": "src/facade/simulate-capture.ts",
8018
8163
  "kind": "type"
8019
8164
  },
8165
+ {
8166
+ "name": "SimulateCaptureFastOption",
8167
+ "source": "src/facade/simulate-capture.ts",
8168
+ "kind": "type"
8169
+ },
8170
+ {
8171
+ "name": "SimulateCaptureFastReport",
8172
+ "source": "src/facade/simulate-capture.ts",
8173
+ "kind": "type"
8174
+ },
8020
8175
  {
8021
8176
  "name": "SimulateCaptureLensDistortion",
8022
8177
  "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
+ ```