@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
@@ -0,0 +1,50 @@
1
+ # facade/display-view.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
+ ## bindDisplayViewCorrectionStates
6
+
7
+ 2.10 (#447): adds states another realm computed (an export, or `computeCorrectionStates` results) to this realm's cache and
8
+ returns the number of states added. For each entry, the grid keys its setup does not hold yet are appended; known ones are
9
+ left as they are (a state's values follow from its key, so they are equal). Every entry is checked before the cache is
10
+ touched: `key` a non-empty string, `gridKeys` an Int32Array of grid keys, `values` a Float64Array of 3 × `gridKeys.length`
11
+ finite numbers; otherwise it fails with an InvalidConfigurationError and the cache is unchanged. The cache's bounds apply as
12
+ in a render: an unknown key creates a setup and can evict the least recently used of the four kept, and a setup that
13
+ reaches 65 536 states is cleared before the next one is added. Import only keys a prepared view reported
14
+ (`correctionKey()`), so states a render here will read.
15
+
16
+ ```ts
17
+ export function bindDisplayViewCorrectionStates(entries: readonly DisplayViewCorrectionStateSet[]): number;
18
+ ```
19
+
20
+ This call is synchronous; any supplied provider must follow its explicit synchronous contract.
21
+
22
+ ## DisplayViewCorrectionStateKeys
23
+
24
+ 2.10 (#447): the grid keys of the states a region needs (`PreparedDisplayView.collectCorrectionStates`), ascending.
25
+
26
+ ```ts
27
+ export interface DisplayViewCorrectionStateKeys { key: string; gridKeys: Int32Array }
28
+ ```
29
+
30
+ ## DisplayViewCorrectionStateSet
31
+
32
+ 2.10 (#447): the AHD low-signal correction states of one setup, as a realm sends them to another. `key` is the setup's
33
+ correction key (`PreparedDisplayView.correctionKey()`), `gridKeys[i]` a state's grid key and `values[3·i …]` its three
34
+ values (28 bytes per state). Both arrays are transferable.
35
+
36
+ ```ts
37
+ export interface DisplayViewCorrectionStateSet { key: string; gridKeys: Int32Array; values: Float64Array }
38
+ ```
39
+
40
+ ## serializeDisplayViewCorrectionStates
41
+
42
+ 2.10 (#447): the AHD low-signal correction states this JavaScript realm holds (a Web Worker, a page), one entry per cached
43
+ setup, least recently used first, each state's grid key and three values copied out. Another realm adds them with
44
+ {@link bindDisplayViewCorrectionStates}; a render there then reads them instead of computing them, with the same bytes.
45
+
46
+ ```ts
47
+ export function serializeDisplayViewCorrectionStates(): DisplayViewCorrectionStateSet[];
48
+ ```
49
+
50
+ This call is synchronous; any supplied provider must follow its explicit synchronous contract.
@@ -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;
@@ -30,7 +30,9 @@ export interface DisplayViewResult {
30
30
  * milliseconds (diagnostic only; never affects the samples).
31
31
  */
32
32
  diagnostics: { sampleCount: number; siteEvaluations: number; sceneLookups: number; detailPixelCount: number; uniformPixelCount: number; ahdCorrectedPixelCount: number;
33
- timingsMs: { view: number; total: number } };
33
+ timingsMs: { view: number; total: number };
34
+ /** #395: exact or fast, as requested and as run; 2.11 (#481): plus `execution`, where the render ran (see {@link DisplayViewFastReport}). */
35
+ fast: DisplayViewFastReport };
34
36
  provenance: { scientificStatus: "approximation"; cameraPresetId: string; cameraPresetVersion: string; evidence: readonly EvidenceProvenance[];
35
37
  composedContracts: readonly string[]; limitations: readonly string[] };
36
38
  /** The capture request's assumptions, then `view.definition`, `view.estimation`, `view.noise`, `view.demosaic` and `view.source`. */
@@ -94,7 +96,7 @@ a capture does. `motion.rotation` is a non-zero angular velocity; `sensor.tempor
94
96
 
95
97
  ```ts
96
98
  SIMULATE_CAPTURE_COST_OPTIONS = Object.freeze(["lens.pupilSampling", "lens.projection", "lens.distortion", "lens.vignetting", "lens.psf",
97
- "lens.diffraction", "sensor.antiAliasing", "sensor.pixelAperture.box", "sensor.temporalSampleCount", "motion.rotation", "motion.shutter.rolling", "output.borderHandling.mirror", "output.region",
99
+ "lens.diffraction", "lens.defocus", "sensor.antiAliasing", "sensor.pixelAperture.box", "sensor.temporalSampleCount", "motion.rotation", "motion.shutter.rolling", "output.borderHandling.mirror", "output.region",
98
100
  "output.whiteBalance.auto", "output.demosaic.ahd", "output.highlightMode.reconstruct", "output.colorEncoding.wide-gamut", "output.gamutMapping.perceptual",
99
101
  "output.format.jpeg", "output.format.png", "output.format.dng"] as const)
100
102
  ```
@@ -118,6 +120,16 @@ Version of how the facade builds requests. It changes whenever the same input wo
118
120
  SIMULATE_CAPTURE_FACADE_VERSION = "1.0.0" as const
119
121
  ```
120
122
 
123
+ ## SIMULATE_CAPTURE_FAST_OPTIONS
124
+
125
+ The options that take the exact-or-fast flag (#395), in the path style of {@link SIMULATE_CAPTURE_COST_OPTIONS}: each accepts
126
+ the record form with `fast` and is reported in `diagnostics.fast.applied` when it runs. Every one of them takes the flag,
127
+ whether or not it has a fast method yet; one without runs exact and reports `false`.
128
+
129
+ ```ts
130
+ SIMULATE_CAPTURE_FAST_OPTIONS = Object.freeze(["lens.diffraction", "sensor.antiAliasing", "sensor.pixelAperture.box", "output.demosaic.ahd"] as const)
131
+ ```
132
+
121
133
  ## SIMULATE_DISPLAY_VIEW_DEFAULT_SAMPLES_PER_AXIS
122
134
 
123
135
  Default stratified samples per axis of a display view (`view.samplesPerAxis`): 16 × 16 sampled real pixels per display pixel with detail, 4 × 4 where it is uniform.
@@ -193,6 +205,14 @@ edge-directed method that reduces zipper and false colour on sharp edges.
193
205
  export type SimulateCaptureDemosaic = "bilinear" | "ahd";
194
206
  ```
195
207
 
208
+ ## SimulateCaptureDemosaicRecord
209
+
210
+ `output.demosaic` as a record (#395): the demosaic and its `fast` override (see {@link SimulateCaptureOptions.fast}).
211
+
212
+ ```ts
213
+ export interface SimulateCaptureDemosaicRecord { kind: SimulateCaptureDemosaic; fast?: boolean }
214
+ ```
215
+
196
216
  ## SimulateCaptureDngPart
197
217
 
198
218
  One part of a whole-frame DNG (#391): a region render's packed RAW and where its native sites lie (`result.raw`, `result.region`).
@@ -212,6 +232,29 @@ The exact contract is declared below; use the domain guide for assumptions and s
212
232
  export type SimulateCaptureExposureMode = "manual" | "aperture-priority" | "shutter-priority" | "program";
213
233
  ```
214
234
 
235
+ ## SimulateCaptureFastOption
236
+
237
+ The exact contract is declared below; use the domain guide for assumptions and staged integration.
238
+
239
+ ```ts
240
+ export type SimulateCaptureFastOption = typeof SIMULATE_CAPTURE_FAST_OPTIONS[number];
241
+ ```
242
+
243
+ ## SimulateCaptureFastReport
244
+
245
+ `diagnostics.fast` of a capture or display view (#395): what was asked for and what ran.
246
+
247
+ ```ts
248
+ export interface SimulateCaptureFastReport {
249
+ /** True when `fast: true` was given at the top level or in any option's record. */
250
+ requested: boolean;
251
+ /** Each fast-capable option that ran, in {@link SIMULATE_CAPTURE_FAST_OPTIONS} order: true where its fast method ran. */
252
+ applied: Readonly<Partial<Record<SimulateCaptureFastOption, boolean>>>;
253
+ /** `engine-reference` when every option ran exact; `approximation-with-a-priori-bound` when any fast method ran (the WebGPU execution record's values). */
254
+ assurance: "engine-reference" | "approximation-with-a-priori-bound";
255
+ }
256
+ ```
257
+
215
258
  ## SimulateCaptureLensDistortion
216
259
 
217
260
  The exact contract is declared below; use the domain guide for assumptions and staged integration.
@@ -280,6 +323,17 @@ export interface SimulateCaptureOptions {
280
323
  * the longest spectral node, capped at 32 sites. Not combinable with `psf` or `pupilSampling`. Default off.
281
324
  */
282
325
  diffraction?: SimulateCaptureLensDiffraction;
326
+ /**
327
+ * Opt-in (#492): defocus of the flat scene plane when `focusDistanceM` differs from the subject distance, as a
328
+ * geometric disc (`model: "geometric-disc"`): the thin-lens blur circle of an ideal uniform circular pupil
329
+ * (`calculateDefocusCircle`), an approximation. The blur diameter is recorded in the `lens.defocus` assumption.
330
+ * `simulateCapture` renders the blur as an object-space convolution of the scene radiance on the site lattice and
331
+ * `simulateDisplayView` as a site kernel in its expected signal; with `diffraction` each spectral node's diffraction
332
+ * kernel is convolved with the disc (a further approximation). In focus the result is that of the same request
333
+ * without the option, plus the assumption.
334
+ * Not combinable with `pupilSampling` or `psf`. Default off.
335
+ */
336
+ defocus?: { model: "geometric-disc" };
283
337
  };
284
338
  exposure?: {
285
339
  /** Default "manual". */
@@ -291,8 +345,12 @@ export interface SimulateCaptureOptions {
291
345
  /** Exposure compensation applied to the meter target, in stops. Default 0. */
292
346
  compensationStops?: number;
293
347
  };
294
- /** Required: an engine chart (for example `{ preset: "uniform" }`, an 18 % grey card) or a caller reflectance/radiance function. */
295
- scene: ChartScene | CallerReflectanceScene | CallerRadianceScene | CallerMaterialScene;
348
+ /**
349
+ * Required: an engine chart (for example `{ preset: "uniform" }`, an 18 % grey card), a declared `material-layers` scene (#491:
350
+ * a chart under shape-mask layers, as `resolveChartMaterialLayers` takes it; the capture is that of its `callerScene`, byte for
351
+ * byte, and the display view can render it on the GPU), or a caller reflectance, radiance or material function.
352
+ */
353
+ scene: ChartScene | ChartMaterialLayerScene | CallerReflectanceScene | CallerRadianceScene | CallerMaterialScene;
296
354
  /** Distance from the camera to the scene plane in metres. Default 5. */
297
355
  subjectDistanceM?: number;
298
356
  /**
@@ -332,8 +390,8 @@ export interface SimulateCaptureOptions {
332
390
  * through `prepareRgbGamutMapping`: constant CIELAB L* and hue, chroma above 90 % of the boundary compressed.
333
391
  */
334
392
  gamutMapping?: "clip" | "perceptual";
335
- /** Default: the 1.0 facade's bilinear RGGB kernels. */
336
- demosaic?: SimulateCaptureDemosaic;
393
+ /** Default: the 1.0 facade's bilinear RGGB kernels. The record form (#395) adds a `fast` override. */
394
+ demosaic?: SimulateCaptureDemosaic | SimulateCaptureDemosaicRecord;
337
395
  /** Default "margin". */
338
396
  borderHandling?: SimulateCaptureBorderHandling;
339
397
  /** DNG only: optional capture-event time (YYYY-MM-DDTHH:mm:ss.sssZ); without it no date tags are written. */
@@ -391,6 +449,13 @@ export interface SimulateCaptureOptions {
391
449
  */
392
450
  pixelAperture?: SimulateCapturePixelAperture;
393
451
  };
452
+ /**
453
+ * Exact or fast (#395). `false` or omitted: every option runs its exact method, the engine reference. `true`: each option
454
+ * listed in {@link SIMULATE_CAPTURE_FAST_OPTIONS} runs its fast method where it has one, a measured, bounded approximation of
455
+ * the exact one; an option without a fast method runs exact. An option's own record `fast` overrides this for that option
456
+ * only. `diagnostics.fast` reports what was requested and what ran. No option has a fast method yet, so every result is exact.
457
+ */
458
+ fast?: boolean;
394
459
  /** Aborting cancels the running task; the promise rejects with a domain error and returns no partial image. */
395
460
  signal?: AbortSignal;
396
461
  /** Called after each committed RAW, development or JPEG tile. Cannot change output. */
@@ -408,10 +473,10 @@ export type SimulateCaptureOutputFormat = "srgb-8" | "srgb-16" | "jpeg" | "png"
408
473
 
409
474
  ## SimulateCapturePixelAperture
410
475
 
411
- Pixel aperture (2.3): centre sampling, or the square photosite integrated with an N × N midpoint rule.
476
+ Pixel aperture (2.3): centre sampling, or the square photosite integrated with an N × N midpoint rule; `fast` (#395) overrides the top-level flag.
412
477
 
413
478
  ```ts
414
- export type SimulateCapturePixelAperture = "point" | "box" | { kind: "box"; samplesPerAxis?: number };
479
+ export type SimulateCapturePixelAperture = "point" | "box" | { kind: "box"; samplesPerAxis?: number; fast?: boolean };
415
480
  ```
416
481
 
417
482
  ## SimulateCaptureProgress
@@ -524,14 +589,18 @@ export interface SimulateCaptureResult {
524
589
  * `diffraction` (the object-space convolution of `lens.diffraction`; part of `raw` and `whiteBalance`), `demosaic`
525
590
  * (the AHD demosaic; part of `development`) and `encode` (PNG, JPEG or DNG serialization), with sub-millisecond
526
591
  * resolution where the host has `performance.now()`. Timings vary from run to run and never enter any digest or output byte.
592
+ * #492: `defocus`, the object-space convolution of `lens.defocus` out of focus (with `lens.diffraction` the combined
593
+ * kernel's convolution, reported here instead of under `diffraction`).
527
594
  */
528
- timingsMs: { raw: number; whiteBalance: number; development: number; jpeg: number; total: number; diffraction?: number; demosaic?: number; encode?: number };
595
+ timingsMs: { raw: number; whiteBalance: number; development: number; jpeg: number; total: number; diffraction?: number; defocus?: number; demosaic?: number; encode?: number };
529
596
  /**
530
597
  * 2.1: the opt-in options that changed the work of this run, in a fixed order (see `SIMULATE_CAPTURE_COST_OPTIONS`).
531
598
  * Empty for a capture with every default. With `timingsMs` it lets an application measure each option's cost on
532
599
  * the user's device.
533
600
  */
534
601
  options: readonly SimulateCaptureCostOption[];
602
+ /** #395: exact or fast, as requested and as run (see {@link SimulateCaptureFastReport}). */
603
+ fast: SimulateCaptureFastReport;
535
604
  };
536
605
  provenance: {
537
606
  scientificStatus: "approximation";
@@ -559,9 +628,9 @@ frequency 1/(2·pitch)).
559
628
 
560
629
  ```ts
561
630
  export type SimulateCaptureSensorAntiAliasing =
562
- | { kind: "four-spot"; separationSites?: number }
563
- | { kind: "two-spot"; axis: "horizontal" | "vertical"; separationSites?: number }
564
- | { kind: "point-splitting"; components: readonly AntiAliasingPointSplitComponent[] };
631
+ | { kind: "four-spot"; separationSites?: number; fast?: boolean }
632
+ | { kind: "two-spot"; axis: "horizontal" | "vertical"; separationSites?: number; fast?: boolean }
633
+ | { kind: "point-splitting"; components: readonly AntiAliasingPointSplitComponent[]; fast?: boolean };
565
634
  ```
566
635
 
567
636
  ## SimulateCaptureWhiteBalance
@@ -11,8 +11,38 @@ setup: use it to render one view in many regions, for example on each worker of
11
11
 
12
12
  ```ts
13
13
  export interface PreparedDisplayView {
14
- /** Renders a view of the prepared request. Renders may run concurrently; they share no state except read-only setup. */
14
+ /**
15
+ * Renders a view of the prepared request. Renders may run concurrently; they share no state except read-only setup and the
16
+ * realm's AHD correction states, which never change a byte (docs/DISPLAY_VIEW.md, "AHD at low signal"). With `gpu: "auto"`
17
+ * or `"require"` (#481) GPU renders of one prepared view run one at a time on its device, and `diagnostics.fast.execution`
18
+ * says whether the GPU or the CPU reference rendered the view, and why.
19
+ */
15
20
  render(view: SimulateDisplayViewOptions, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewResult>;
21
+ /**
22
+ * 2.11 (#481): releases the WebGPU device the view acquired (none with `gpu: "off"`, or when `gpuDevice` gave an accelerator,
23
+ * whose device its owner keeps). Later renders run the CPU reference labelled `fallbackReason: "disposed"` (`"auto"`) or fail
24
+ * with that reason (`"require"`). Idempotent.
25
+ */
26
+ dispose(): void;
27
+ /**
28
+ * 2.10 (#447): the key of this request's AHD low-signal correction states, or null when the request has no AHD
29
+ * (`output.demosaic` other than "ahd"). Every input of the key is fixed when the request is prepared; two prepared views
30
+ * with the same key read the same states.
31
+ */
32
+ correctionKey(): string | null;
33
+ /**
34
+ * 2.10 (#447): the grid keys of every correction state a render of `view` reads (ascending, whether or not this realm holds
35
+ * them), found by a render of the view's region that records the states instead of computing them. No image is returned;
36
+ * it costs about one render whose states are all held. Fails with an InvalidConfigurationError when the request has no AHD.
37
+ */
38
+ collectCorrectionStates(view: SimulateDisplayViewOptions, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewCorrectionStateKeys>;
39
+ /**
40
+ * 2.10 (#447): computes the correction states of `gridKeys` (from `collectCorrectionStates`, or a share of them) as a render
41
+ * would, stores them in this realm's cache and returns their values, for {@link bindDisplayViewCorrectionStates} in
42
+ * another realm. States this realm holds are read, not computed. Yields and honours `signal` like `render`. Fails with an
43
+ * InvalidConfigurationError when the request has no AHD or a grid key is out of range.
44
+ */
45
+ computeCorrectionStates(gridKeys: Int32Array, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewCorrectionStateSet>;
16
46
  }
17
47
  ```
18
48
 
@@ -35,8 +65,15 @@ responses through the environment chain, the diffraction kernels, readout moment
35
65
  about 0.3–1.3 s per call on a 24 MP request; a region costs only its own pixels. Errors in the request are raised here;
36
66
  errors in the view by `render`.
37
67
 
68
+ 2.11 (#481): `prepareOptions.gpu` chooses the renderer: `"off"` (default) is the CPU reference, today's bytes; `"auto"` renders
69
+ on WebGPU when a conforming device is available and the request is supported, else on the CPU, labelled; `"require"` fails
70
+ instead of falling back (`ImageKernelExecutionError`, acquisition failures here, later ones from `render`). `gpuDevice` is a
71
+ WebGPU entry point or an `ImageKernelAccelerator` whose device the view shares; without it the engine acquires one device
72
+ for the prepared view (the request's `signal` aborts the acquisition) and `dispose()` releases it. The realm's
73
+ `setWebGpuEnabled(false)` vetoes both GPU modes (`webgpu-disabled`). See docs/DISPLAY_VIEW.md, "Rendering on the GPU".
74
+
38
75
  ```ts
39
- export async function prepareDisplayView(options: SimulateCaptureOptions): Promise<PreparedDisplayView>;
76
+ export async function prepareDisplayView(options: SimulateCaptureOptions, prepareOptions?: PrepareDisplayViewOptions): Promise<PreparedDisplayView>;
40
77
  ```
41
78
 
42
79
  This call is asynchronous; byte hashing uses the caller runtime's Web Crypto.
@@ -71,6 +71,8 @@ export interface ImageKernelAccelerator {
71
71
  readonly backend: ImageKernelBackend;
72
72
  readonly requestedBackend: ImageKernelBackend;
73
73
  readonly fallbackReason: ImageKernelFallbackReason | null;
74
+ /** #481: the adapter of a `webgpu-f32` accelerator's device (null for `cpu-reference`, or when the browser gives no `GPUAdapter.info`). */
75
+ readonly adapter: ImageKernelAdapterDescription | null;
74
76
  readonly state: ImageKernelAcceleratorState;
75
77
  renderNativeCaptureSdr(input: NativeCaptureSdrInput, provider: NativeCaptureSdrProvider, options?: ImageKernelRunOptions): Promise<AcceleratedNativeCaptureSdrOutput>;
76
78
  /** Takes ownership of `input.raw` exactly like `createNativeRawDevelopmentTask` (the caller's arrays are detached). */
@@ -93,9 +95,14 @@ The exact contract is declared below; use the domain guide for assumptions and s
93
95
 
94
96
  ```ts
95
97
  export interface ImageKernelAcceleratorOptions {
96
- /** Requested backend. `cpu-reference` is the reference and never touches WebGPU. */
97
- backend: ImageKernelBackend;
98
- /** Required with `webgpu-f32`: use the CPU reference (labelled) or fail when WebGPU cannot be acquired. */
98
+ /**
99
+ * The one-boolean form. `true` is `backend: "webgpu-f32"` with `fallback: "cpu-reference"` unless `fallback` is given;
100
+ * `false` is `backend: "cpu-reference"`. Give `webgpu` or `backend`, not both.
101
+ */
102
+ webgpu?: boolean;
103
+ /** Requested backend. `cpu-reference` is the reference and never touches WebGPU. Required unless `webgpu` is given. */
104
+ backend?: ImageKernelBackend;
105
+ /** Required with `backend: "webgpu-f32"`: use the CPU reference (labelled) or fail when WebGPU cannot be acquired. */
99
106
  fallback?: "cpu-reference" | "fail";
100
107
  /** WebGPU entry point; defaults to `navigator.gpu`. Supply a worker's `navigator.gpu` explicitly if needed. */
101
108
  gpu?: unknown;
@@ -2,6 +2,58 @@
2
2
 
3
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
4
 
5
+ ## ChartCompositeProbeComponent
6
+
7
+ A component of the composite chart kernel's double-float32 probe (see {@link ChartCompositeProbeRecord}). The first four are the
8
+ outputs of the probe before 2.11.0: `two-sum` is TwoSum's low part (`s.l`), `two-product` Dekker's TwoProduct low part (`m.l`),
9
+ `double-word-add` the double-word sum's low part (`a.l`), `double-word-multiply` the Dekker double-word product (`q.h`, `q.l`).
10
+
11
+ ```ts
12
+ export type ChartCompositeProbeComponent = "two-sum" | "two-product" | "double-word-add" | "double-word-multiply" | "fma-two-product" | "fma-double-word-multiply";
13
+ ```
14
+
15
+ ## ChartCompositeProbeMismatch
16
+
17
+ One probe output that differs from its expected value: the component, the probe input's index, and the float32 bits (hex).
18
+
19
+ ```ts
20
+ export interface ChartCompositeProbeMismatch {
21
+ component: ChartCompositeProbeComponent;
22
+ input: number;
23
+ got: string;
24
+ want: string;
25
+ }
26
+ ```
27
+
28
+ ## ChartCompositeProbeRecord
29
+
30
+ The composite chart kernel's device probe (docs/WEBGPU.md, "Scene radiance on the GPU"): how the device evaluated the kernel's
31
+ double-float32 building blocks, and which product path the kernel was compiled with. Diagnostic; it never changes a result.
32
+
33
+ - `deviceClass`: `exact` (the written order, round to nearest); `contracted` (only the Dekker product paths differ, consistent
34
+ with a multiply and an add fused into one rounding); `reassociated` (a sum path differs and every differing sum low part is
35
+ zero, the value an algebraic simplification of (a + b) − a to b gives); `other` (anything else, such as a sum path that differs
36
+ with non-zero low parts, as a rounding not to nearest gives, or a non-finite output).
37
+ - `productPath`: `dekker` when the Dekker path passes, else `fma` when the fma path passes (which needs a fused `fma`), else null
38
+ (the device is refused for composite charts, the 2.3 elements and material-layers scenes).
39
+ - `fmaFused`: whether every fma TwoProduct low part was exact (a fused `fma`; WGSL also allows an unfused one).
40
+
41
+ ```ts
42
+ export interface ChartCompositeProbeRecord {
43
+ deviceClass: "exact" | "contracted" | "reassociated" | "other";
44
+ productPath: "dekker" | "fma" | null;
45
+ fmaFused: boolean;
46
+ /** Probe inputs, each checked on every component. */
47
+ inputs: number;
48
+ /** Differing outputs per component. */
49
+ mismatchCounts: Readonly<Record<ChartCompositeProbeComponent, number>>;
50
+ /** The indices of the probe inputs (`PROBE_INPUTS`) whose output differs, per component. */
51
+ mismatchedInputs: Readonly<Record<ChartCompositeProbeComponent, readonly number[]>>;
52
+ /** The first differing outputs (at most eight), in component order. */
53
+ mismatches: readonly ChartCompositeProbeMismatch[];
54
+ }
55
+ ```
56
+
5
57
  ## composeRelativeErrorBounds
6
58
 
7
59
  Composes two `relative-to-reference` bounds through a pipeline `second ∘ first`, where the second
@@ -17,6 +69,20 @@ export function composeRelativeErrorBounds(first: ImageKernelRelativeErrorBound,
17
69
 
18
70
  This call is synchronous; any supplied provider must follow its explicit synchronous contract.
19
71
 
72
+ ## ImageKernelAdapterDescription
73
+
74
+ #481: the WebGPU adapter a device came from, as `GPUAdapter.info` describes it (W3C WebGPU, `GPUAdapterInfo`): each field
75
+ is the browser's string, or empty when the browser withholds it. Diagnostic only; it never changes a result.
76
+
77
+ ```ts
78
+ export interface ImageKernelAdapterDescription {
79
+ vendor: string;
80
+ architecture: string;
81
+ device: string;
82
+ description: string;
83
+ }
84
+ ```
85
+
20
86
  ## ImageKernelBackend
21
87
 
22
88
  Requested or actual execution backend.
@@ -51,6 +117,11 @@ export interface ImageKernelExecution {
51
117
  fallbackReason: ImageKernelFallbackReason | null;
52
118
  arithmetic: "float64" | "float32";
53
119
  assurance: "engine-reference" | "approximation-with-a-priori-bound";
120
+ /**
121
+ * The exact-or-fast flag in the facade's words (#395): false for `cpu-reference` (the engine reference), true for
122
+ * `webgpu-f32` (a bounded approximation). `backend` still names where the work ran.
123
+ */
124
+ fast: boolean;
54
125
  /**
55
126
  * True only for `cpu-reference`. Bit-exact identities (SHA-256 artifact bindings, byte-parity fixtures,
56
127
  * cross-engine determinism hashes) are CPU-only and must never be computed from a `webgpu-f32` result.
@@ -87,19 +158,20 @@ export class ImageKernelExecutionError extends Error {
87
158
 
88
159
  ## ImageKernelFailureReason
89
160
 
90
- Failure classes reported by {@link ImageKernelExecutionError}.
161
+ Failure classes reported by {@link ImageKernelExecutionError}. `conformance-failed` (#481): a device failed the display view's
162
+ run-time self-check with `gpu: "require"`.
91
163
 
92
164
  ```ts
93
165
  export type ImageKernelFailureReason = ImageKernelFallbackReason | "device-lost" | "out-of-memory" | "gpu-validation" |
94
- "aborted" | "disposed" | "busy" | "unsupported-on-backend" | "unsupported-float32-domain" | "indeterminate-float32-classification";
166
+ "aborted" | "disposed" | "busy" | "unsupported-on-backend" | "unsupported-float32-domain" | "indeterminate-float32-classification" | "conformance-failed";
95
167
  ```
96
168
 
97
169
  ## ImageKernelFallbackReason
98
170
 
99
- Why a requested WebGPU backend was not used (only with `fallback: "cpu-reference"`).
171
+ Why a requested `webgpu-f32` backend ran the CPU reference instead. `webgpu-disabled`: `setWebGpuEnabled(false)` in this realm.
100
172
 
101
173
  ```ts
102
- export type ImageKernelFallbackReason = "webgpu-unavailable" | "adapter-unavailable" | "device-request-failed" |
174
+ export type ImageKernelFallbackReason = "webgpu-unavailable" | "webgpu-disabled" | "adapter-unavailable" | "device-request-failed" |
103
175
  "insufficient-limits" | "unsupported-platform-endianness";
104
176
  ```
105
177
 
@@ -0,0 +1,23 @@
1
+ # gpu/webgpu-switch.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
+ ## getWebGpuEnabled
6
+
7
+ Whether this realm may use WebGPU when a caller asks for it.
8
+
9
+ ```ts
10
+ export function getWebGpuEnabled(): boolean;
11
+ ```
12
+
13
+ This call is synchronous; any supplied provider must follow its explicit synchronous contract.
14
+
15
+ ## setWebGpuEnabled
16
+
17
+ Turns WebGPU on (`true`, the default) or off (`false`) for this realm. Anything but a boolean is refused.
18
+
19
+ ```ts
20
+ export function setWebGpuEnabled(enabled: boolean): void;
21
+ ```
22
+
23
+ This call is synchronous; any supplied provider must follow its explicit synchronous contract.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@photivra/engine",
3
- "version": "2.9.0",
3
+ "version": "2.11.1",
4
4
  "private": false,
5
5
  "description": "Scientific TypeScript engine for camera optics, exposure, focus, motion, sensor sampling, diffraction, and digital imaging calculations.",
6
6
  "type": "module",
@@ -88,6 +88,8 @@
88
88
  "bench:webgpu": "vitest run --config vitest.webgpu-timing.config.ts",
89
89
  "test:webgpu:hardware": "node scripts/run-webgpu-hardware.mjs test",
90
90
  "bench:webgpu:hardware": "node scripts/run-webgpu-hardware.mjs bench",
91
+ "accept:gpu": "node scripts/accept-display-view-gpu.mjs --gpu",
92
+ "accept:gpu:hardware": "node scripts/accept-display-view-gpu.mjs --gpu --hardware",
91
93
  "check:browser-surface": "node scripts/check-browser-surface.mjs",
92
94
  "check:licenses": "node scripts/check-license-policy.mjs",
93
95
  "check:license-headers": "node scripts/check-license-headers.mjs",