@photivra/engine 2.19.0 → 2.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +289 -1
- package/CITATION.cff +1 -1
- package/NODE_SUPPORT.md +7 -5
- package/README.md +7 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +21 -10
- package/dist/capture/dng-lens-correction-opcodes.d.ts +32 -0
- package/dist/capture/dng-lens-correction-opcodes.js +119 -0
- package/dist/capture/dng-lens-correction-opcodes.js.map +1 -0
- package/dist/capture/exposure-build-up-stage.d.ts +16 -0
- package/dist/capture/exposure-build-up-stage.js +4 -0
- package/dist/capture/exposure-build-up-stage.js.map +1 -0
- package/dist/capture/native-environment-lean.d.ts +2 -1
- package/dist/capture/native-environment-lean.js +42 -78
- package/dist/capture/native-environment-lean.js.map +1 -1
- package/dist/capture/native-environment-tabulated.js +4 -3
- package/dist/capture/native-environment-tabulated.js.map +1 -1
- package/dist/capture/native-raw-dng.d.ts +6 -0
- package/dist/capture/native-raw-dng.js +16 -2
- package/dist/capture/native-raw-dng.js.map +1 -1
- package/dist/capture/native-raw.d.ts +3 -2
- package/dist/capture/native-raw.js +5 -4
- package/dist/capture/native-raw.js.map +1 -1
- package/dist/capture/sensor-raw-producer.d.ts +4 -1
- package/dist/capture/sensor-raw-producer.js +15 -8
- package/dist/capture/sensor-raw-producer.js.map +1 -1
- package/dist/core/shared-helpers.d.ts +2 -0
- package/dist/core/shared-helpers.js +4 -0
- package/dist/core/shared-helpers.js.map +1 -1
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/core/version.js.map +1 -1
- package/dist/equipment/generic-lens-catalogue.d.ts +11 -4
- package/dist/equipment/generic-lens-catalogue.js +49 -7
- package/dist/equipment/generic-lens-catalogue.js.map +1 -1
- package/dist/equipment/generic-tier-assets.d.ts +32 -0
- package/dist/equipment/generic-tier-assets.js +18 -14
- package/dist/equipment/generic-tier-assets.js.map +1 -1
- package/dist/equipment/generic-tier-presets.js +2 -3
- package/dist/equipment/generic-tier-presets.js.map +1 -1
- package/dist/equipment/sensor-profile-body.d.ts +78 -0
- package/dist/equipment/sensor-profile-body.js +77 -0
- package/dist/equipment/sensor-profile-body.js.map +1 -0
- package/dist/equipment/sensor-profiles.d.ts +8 -0
- package/dist/equipment/sensor-profiles.js +82 -0
- package/dist/equipment/sensor-profiles.js.map +1 -0
- package/dist/facade/catalogue-lens-signal.d.ts +2 -2
- package/dist/facade/catalogue-lens-signal.js +58 -71
- package/dist/facade/catalogue-lens-signal.js.map +1 -1
- package/dist/facade/chart-radiance-batch.js +2 -1
- package/dist/facade/chart-radiance-batch.js.map +1 -1
- package/dist/facade/defocus-image-space-provider.d.ts +7 -0
- package/dist/facade/defocus-image-space-provider.js +64 -76
- package/dist/facade/defocus-image-space-provider.js.map +1 -1
- package/dist/facade/display-view-gpu-session.js +2 -0
- package/dist/facade/display-view-gpu-session.js.map +1 -1
- package/dist/facade/display-view-gpu.d.ts +13 -5
- package/dist/facade/display-view-gpu.js +4 -4
- package/dist/facade/display-view-gpu.js.map +1 -1
- package/dist/facade/display-view-lens-signal.d.ts +1 -1
- package/dist/facade/display-view-lens-signal.js +30 -26
- package/dist/facade/display-view-lens-signal.js.map +1 -1
- package/dist/facade/display-view.d.ts +3 -1
- package/dist/facade/display-view.js +6 -24
- package/dist/facade/display-view.js.map +1 -1
- package/dist/facade/expected-signal-setup.d.ts +3 -1
- package/dist/facade/expected-signal-setup.js +1 -1
- package/dist/facade/expected-signal-setup.js.map +1 -1
- package/dist/facade/expected-signal.d.ts +47 -14
- package/dist/facade/expected-signal.js +117 -112
- package/dist/facade/expected-signal.js.map +1 -1
- package/dist/facade/exposure-build-up.d.ts +70 -0
- package/dist/facade/exposure-build-up.js +164 -0
- package/dist/facade/exposure-build-up.js.map +1 -0
- package/dist/facade/fast-methods.d.ts +50 -0
- package/dist/facade/fast-methods.js +58 -0
- package/dist/facade/fast-methods.js.map +1 -0
- package/dist/facade/fast-resolution.d.ts +12 -0
- package/dist/facade/fast-resolution.js +18 -0
- package/dist/facade/fast-resolution.js.map +1 -0
- package/dist/facade/generic-lens-capture.d.ts +5 -4
- package/dist/facade/generic-lens-capture.js +5 -4
- package/dist/facade/generic-lens-capture.js.map +1 -1
- package/dist/facade/image-plane-enable.d.ts +7 -0
- package/dist/facade/image-plane-enable.js +17 -0
- package/dist/facade/image-plane-enable.js.map +1 -0
- package/dist/facade/image-plane-lattice-data.d.ts +6 -0
- package/dist/facade/image-plane-lattice-data.js +10 -0
- package/dist/facade/image-plane-lattice-data.js.map +1 -0
- package/dist/facade/image-plane-support.d.ts +33 -0
- package/dist/facade/image-plane-support.js +11 -0
- package/dist/facade/image-plane-support.js.map +1 -0
- package/dist/facade/image-plane.d.ts +36 -0
- package/dist/facade/image-plane.js +353 -0
- package/dist/facade/image-plane.js.map +1 -0
- package/dist/facade/mixed-illumination.d.ts +108 -0
- package/dist/facade/mixed-illumination.js +174 -0
- package/dist/facade/mixed-illumination.js.map +1 -0
- package/dist/facade/representative-light-sources.d.ts +72 -0
- package/dist/facade/representative-light-sources.js +124 -0
- package/dist/facade/representative-light-sources.js.map +1 -0
- package/dist/facade/scene-radiance.d.ts +129 -4
- package/dist/facade/scene-radiance.js +48 -13
- package/dist/facade/scene-radiance.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +88 -19
- package/dist/facade/simulate-capture.js +374 -145
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.d.ts +3 -2
- package/dist/facade/simulate-display-view.js +36 -18
- package/dist/facade/simulate-display-view.js.map +1 -1
- package/dist/gpu/chart-composite-gpu.d.ts +13 -1
- package/dist/gpu/chart-composite-gpu.js +48 -9
- package/dist/gpu/chart-composite-gpu.js.map +1 -1
- package/dist/gpu/chart-radiance-gpu.js +4 -30
- package/dist/gpu/chart-radiance-gpu.js.map +1 -1
- package/dist/gpu/display-view-composite-material-module.d.ts +10 -4
- package/dist/gpu/display-view-composite-material-module.js +39 -13
- package/dist/gpu/display-view-composite-material-module.js.map +1 -1
- package/dist/gpu/display-view-image-material-module.d.ts +86 -0
- package/dist/gpu/display-view-image-material-module.js +339 -0
- package/dist/gpu/display-view-image-material-module.js.map +1 -0
- package/dist/gpu/display-view-image-quality.d.ts +45 -0
- package/dist/gpu/display-view-image-quality.js +380 -0
- package/dist/gpu/display-view-image-quality.js.map +1 -0
- package/dist/gpu/display-view-quality-gpu.d.ts +67 -1
- package/dist/gpu/display-view-quality-gpu.js +136 -205
- package/dist/gpu/display-view-quality-gpu.js.map +1 -1
- package/dist/gpu/display-view-speed-gpu.d.ts +51 -3
- package/dist/gpu/display-view-speed-gpu.js +131 -93
- package/dist/gpu/display-view-speed-gpu.js.map +1 -1
- package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +29 -15
- package/dist/gpu/wgsl-display-view-quality-kernel.js +58 -36
- package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
- package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +21 -6
- package/dist/gpu/wgsl-display-view-speed-kernel.js +46 -11
- package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
- package/dist/gpu/wgsl-exact-sum.d.ts +20 -0
- package/dist/gpu/wgsl-exact-sum.js +42 -0
- package/dist/gpu/wgsl-exact-sum.js.map +1 -0
- package/dist/index.d.ts +18 -3
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/motion/subject-motion.d.ts +66 -0
- package/dist/motion/subject-motion.js +52 -0
- package/dist/motion/subject-motion.js.map +1 -0
- package/dist/optics/aperture-diameter.d.ts +47 -0
- package/dist/optics/aperture-diameter.js +50 -0
- package/dist/optics/aperture-diameter.js.map +1 -0
- package/dist/optics/detail-limit.d.ts +182 -0
- package/dist/optics/detail-limit.js +336 -0
- package/dist/optics/detail-limit.js.map +1 -0
- package/dist/optics/generic-lens-lateral-color.d.ts +83 -0
- package/dist/optics/generic-lens-lateral-color.js +77 -0
- package/dist/optics/generic-lens-lateral-color.js.map +1 -0
- package/dist/optics/generic-lens-psf.d.ts +18 -2
- package/dist/optics/generic-lens-psf.js +79 -48
- package/dist/optics/generic-lens-psf.js.map +1 -1
- package/dist/optics/lens-psf-profile.d.ts +7 -0
- package/dist/optics/lens-psf-profile.js +2 -1
- package/dist/optics/lens-psf-profile.js.map +1 -1
- package/dist/optics/scene-to-sensor-irradiance.d.ts +13 -0
- package/dist/optics/scene-to-sensor-irradiance.js +7 -0
- package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
- package/dist/output/crop-to-match-focal-length.d.ts +62 -0
- package/dist/output/crop-to-match-focal-length.js +63 -0
- package/dist/output/crop-to-match-focal-length.js.map +1 -0
- package/dist/output/developed-lens-corrections.d.ts +19 -5
- package/dist/output/developed-lens-corrections.js +30 -11
- package/dist/output/developed-lens-corrections.js.map +1 -1
- package/dist/output/generic-lens-corrections.d.ts +41 -3
- package/dist/output/generic-lens-corrections.js +57 -9
- package/dist/output/generic-lens-corrections.js.map +1 -1
- package/dist/output/lens-corrections.d.ts +12 -2
- package/dist/output/lens-corrections.js +22 -7
- package/dist/output/lens-corrections.js.map +1 -1
- package/dist/output/print-contrast-reference.js +1 -1
- package/dist/output/print-contrast-reference.js.map +1 -1
- package/dist/output/print-plan.d.ts +41 -5
- package/dist/output/print-plan.js +59 -14
- package/dist/output/print-plan.js.map +1 -1
- package/dist/output/print-size-blur-noise.d.ts +110 -0
- package/dist/output/print-size-blur-noise.js +138 -0
- package/dist/output/print-size-blur-noise.js.map +1 -0
- package/dist/sensor/binomial-sample.d.ts +3 -0
- package/dist/sensor/binomial-sample.js +86 -0
- package/dist/sensor/binomial-sample.js.map +1 -0
- package/dist/sensor/eqe-electron-rate.js +1 -7
- package/dist/sensor/eqe-electron-rate.js.map +1 -1
- package/dist/sensor/exposure-window.d.ts +2 -0
- package/dist/sensor/exposure-window.js +2 -2
- package/dist/sensor/exposure-window.js.map +1 -1
- package/dist/sensor/readout-timing.js +2 -23
- package/dist/sensor/readout-timing.js.map +1 -1
- package/dist/sensor/response-application-compatibility.js +1 -6
- package/dist/sensor/response-application-compatibility.js.map +1 -1
- package/dist/sensor/responsivity-photocurrent.js +1 -7
- package/dist/sensor/responsivity-photocurrent.js.map +1 -1
- package/dist/sensor/sensor-characteristics.d.ts +147 -0
- package/dist/sensor/sensor-characteristics.js +126 -0
- package/dist/sensor/sensor-characteristics.js.map +1 -0
- package/dist/sensor/spatial-sample-reduction.js +1 -5
- package/dist/sensor/spatial-sample-reduction.js.map +1 -1
- package/dist/sensor/spectral-quadrature.js +1 -6
- package/dist/sensor/spectral-quadrature.js.map +1 -1
- package/dist/sensor/temporal-photo-signal.d.ts +3 -0
- package/dist/sensor/temporal-photo-signal.js +5 -2
- package/dist/sensor/temporal-photo-signal.js.map +1 -1
- package/dist/stabilization/system.d.ts +9 -0
- package/dist/stabilization/system.js +5 -6
- package/dist/stabilization/system.js.map +1 -1
- package/docs/AGENT_GUIDE.md +5 -0
- package/docs/API_REFERENCE.md +173 -2
- package/docs/QUICK_START.md +213 -6
- package/docs/USAGE.md +157 -3
- package/docs/api/capture-native-raw-dng.md +6 -0
- package/docs/api/core-version.md +1 -1
- package/docs/api/equipment-generic-lens-catalogue.md +17 -7
- package/docs/api/equipment-sensor-profile-body.md +64 -0
- package/docs/api/equipment-sensor-profiles.md +86 -0
- package/docs/api/exports.json +357 -2
- package/docs/api/facade-display-view-gpu.md +5 -2
- package/docs/api/facade-exposure-build-up.md +105 -0
- package/docs/api/facade-fast-methods.md +99 -0
- package/docs/api/facade-image-plane-enable.md +16 -0
- package/docs/api/facade-mixed-illumination.md +67 -0
- package/docs/api/facade-representative-light-sources.md +131 -0
- package/docs/api/facade-scene-radiance.md +54 -3
- package/docs/api/facade-simulate-capture.md +60 -15
- package/docs/api/facade-simulate-display-view.md +3 -2
- package/docs/api/motion-subject-motion.md +23 -0
- package/docs/api/optics-aperture-diameter.md +51 -0
- package/docs/api/optics-detail-limit.md +203 -0
- package/docs/api/optics-generic-lens-lateral-color.md +79 -0
- package/docs/api/output-crop-to-match-focal-length.md +67 -0
- package/docs/api/output-developed-lens-corrections.md +10 -1
- package/docs/api/output-generic-lens-corrections.md +40 -2
- package/docs/api/output-lens-corrections.md +11 -1
- package/docs/api/output-print-plan.md +35 -1
- package/docs/api/output-print-size-blur-noise.md +115 -0
- package/docs/api/sensor-sensor-characteristics.md +105 -0
- package/llms.txt +6 -0
- package/package.json +1 -1
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* divided by the scale in float64; the kernel multiplies the two axes);
|
|
10
10
|
* 2. for every native site the real pixels' demosaic reads (the footprint plus one site of reach), the expected
|
|
11
11
|
* electrons: the scene material at the pixel aperture's query offsets (the material module, `material_at`), the
|
|
12
|
-
* material's channel signal
|
|
13
|
-
* in the reference's order, plus the dark
|
|
12
|
+
* material's channel signal integrated in the kernel from its spectrum (Σ_λ A_c(λ)·L(λ), `material_signal`), or (#581) the image-plane
|
|
13
|
+
* module's channel signal at the point (`scene_value`), summed over the offsets in the reference's order, plus the dark
|
|
14
|
+
* electrons;
|
|
14
15
|
* 3. the readout moments of each site (mean k·e, variance k²·e + c₀, third cumulant k³·e) and the clip at the white
|
|
15
16
|
* level (the clipped-normal moments, in a cancellation-free standardized form);
|
|
16
17
|
* 4. per real pixel the bilinear kernels, white balance and highlight clip, the colour matrix, the tone curve
|
|
@@ -50,10 +51,16 @@ export const DISPLAY_VIEW_OUTPUT_FLOATS = 11;
|
|
|
50
51
|
export const DISPLAY_VIEW_FLAG_WORDS = 3;
|
|
51
52
|
/**
|
|
52
53
|
* #533: relative bound of a site's float32 mean and variance against the reference's float64, in units of E: the electrons'
|
|
53
|
-
* sum of at most 16 offsets (each term a host-rounded weight and
|
|
54
|
-
* readout's products and sum carry at most 26 E
|
|
54
|
+
* sum of at most 16 offsets (each term a host-rounded weight and a material signal and one product), the dark electrons, and
|
|
55
|
+
* the readout's products and sum carry at most 26 E with a host-rounded material signal (E/2). 2.21.0: the kernel integrates
|
|
56
|
+
* the material signal Σ_n A_c(λ_n)·L_m(λ_n) itself from the host-rounded response and spectrum: each non-negative product
|
|
57
|
+
* carries E/2 + E/2 for its operands and E for its rounding, and the products are summed in blocks of 16 nodes (at most 15
|
|
58
|
+
* additions within a block and 16 across blocks for N ≤ 256 nodes): 33 E instead of E/2, so a site carries at most 58.5 E,
|
|
59
|
+
* inside the unchanged 64.
|
|
55
60
|
*/
|
|
56
61
|
export const DISPLAY_VIEW_SITE_RELATIVE_U = 64;
|
|
62
|
+
/** Most spectral nodes the Speed kernel integrates per site (DISPLAY_VIEW_SITE_RELATIVE_U: 16 blocks of 16). */
|
|
63
|
+
export const DISPLAY_VIEW_SPEED_MAXIMUM_NODES = 256;
|
|
57
64
|
/** Floats per column or row record of the geometry buffer. */
|
|
58
65
|
export const DISPLAY_VIEW_GEOMETRY_STRIDE = 20;
|
|
59
66
|
/** Layout of the aux table (float32 words). */
|
|
@@ -90,7 +97,10 @@ const literal = (value) => {
|
|
|
90
97
|
* The kernel's own WGSL, without the material module. `assembleDisplayViewSpeedWgsl` appends a module that defines
|
|
91
98
|
* `fn material_at(p: vec2<f32>) -> u32` and `var<private> material_uncertain: bool` (set to true when the point's
|
|
92
99
|
* classification is within its bound of a material boundary; the kernel then flags the display pixel for host
|
|
93
|
-
* recomputation)
|
|
100
|
+
* recomputation), and the adapter `scene_value(p, c) = material_signal(material_at(p), c)`. #581: a module may instead define
|
|
101
|
+
* `fn scene_value(p: vec2<f32>, c: u32) -> f32` itself (the image-plane module: the print's channel signal at p) and then
|
|
102
|
+
* declares how many roundings it adds (`DisplayViewGpuMaterialModule.extraSiteRoundings`). The module may declare bindings
|
|
103
|
+
* in @group(1) and use the constants E and SLACK declared here.
|
|
94
104
|
*/
|
|
95
105
|
export const DISPLAY_VIEW_SPEED_KERNEL_WGSL = /* wgsl */ `
|
|
96
106
|
const E: f32 = ${E_LITERAL};
|
|
@@ -104,7 +114,7 @@ const STRIDE: u32 = ${DISPLAY_VIEW_GEOMETRY_STRIDE}u;
|
|
|
104
114
|
struct Params {
|
|
105
115
|
count: u32, row0: u32, region_w: u32, region_x: u32,
|
|
106
116
|
region_y: u32, margin: u32, native_w: u32, native_h: u32,
|
|
107
|
-
columns: u32, tone: u32, offsets: u32,
|
|
117
|
+
columns: u32, tone: u32, offsets: u32, nodes: u32,
|
|
108
118
|
k0: f32, k1: f32, k2: f32, reach2: f32,
|
|
109
119
|
dark0: f32, dark1: f32, dark2: f32, clip_level: f32,
|
|
110
120
|
c0_0: f32, c0_1: f32, c0_2: f32, pad1: f32,
|
|
@@ -116,7 +126,7 @@ m22: f32, scale_u: f32, scale_v: f32, pad3: f32,
|
|
|
116
126
|
@group(0) @binding(0) var<uniform> params: Params;
|
|
117
127
|
@group(0) @binding(1) var<storage, read> aux: array<f32>;
|
|
118
128
|
@group(0) @binding(2) var<storage, read> geometry: array<f32>;
|
|
119
|
-
@group(0) @binding(3) var<storage, read>
|
|
129
|
+
@group(0) @binding(3) var<storage, read> spectral_table: array<f32>;
|
|
120
130
|
@group(0) @binding(4) var<storage, read_write> out: array<f32>;
|
|
121
131
|
@group(0) @binding(5) var<storage, read_write> flags: array<u32>;
|
|
122
132
|
|
|
@@ -239,6 +249,17 @@ fn channel_of(x: i32, y: i32) -> u32 {
|
|
|
239
249
|
if ((y & 1) == 0) { return select(1u, 0u, (x & 1) == 0); }
|
|
240
250
|
return select(2u, 1u, (x & 1) == 0);
|
|
241
251
|
}
|
|
252
|
+
fn material_signal(m: u32, c: u32) -> f32 {
|
|
253
|
+
let n = params.nodes;
|
|
254
|
+
var s = 0.0;
|
|
255
|
+
var b = 0.0;
|
|
256
|
+
for (var k = 0u; k < n; k = k + 1u) {
|
|
257
|
+
b = b + spectral_table[c * n + k] * spectral_table[(3u + m) * n + k];
|
|
258
|
+
if ((k & 15u) == 15u) { s = s + b; b = 0.0; }
|
|
259
|
+
}
|
|
260
|
+
return s + b;
|
|
261
|
+
}
|
|
262
|
+
|
|
242
263
|
|
|
243
264
|
fn site_electrons(x: i32, y: i32, c: u32) -> f32 {
|
|
244
265
|
var sum = 0.0;
|
|
@@ -248,8 +269,7 @@ for (var o = 0u; o < params.offsets; o = o + 1u) {
|
|
|
248
269
|
let base = ${DISPLAY_VIEW_AUX.offsets}u + 4u * o;
|
|
249
270
|
let u = (fx + aux[base]) * params.scale_u;
|
|
250
271
|
let v = (fy + aux[base + 1u]) * params.scale_v;
|
|
251
|
-
|
|
252
|
-
sum = sum + aux[base + 2u] * site_table[m * 3u + c];
|
|
272
|
+
sum = sum + aux[base + 2u] * scene_value(vec2<f32>(u, v), c);
|
|
253
273
|
}
|
|
254
274
|
return sum;
|
|
255
275
|
}
|
|
@@ -420,8 +440,23 @@ flags[3u * i + 1u] = mask0;
|
|
|
420
440
|
flags[3u * i + 2u] = mask1;
|
|
421
441
|
}
|
|
422
442
|
`;
|
|
423
|
-
/**
|
|
443
|
+
/**
|
|
444
|
+
* The channel signal of the material a material module's `material_at` gives (the kernel's `scene_value`), integrated from its
|
|
445
|
+
* spectrum when it changes (2.21.0: signals are integrated from the material spectrum per site).
|
|
446
|
+
*/
|
|
447
|
+
export const DISPLAY_VIEW_MATERIAL_SCENE_VALUE_WGSL = /* wgsl */ `
|
|
448
|
+
var<private> scene_m: u32 = 0xffffffffu;
|
|
449
|
+
var<private> scene_c: u32 = 0u;
|
|
450
|
+
var<private> scene_s: f32 = 0.0;
|
|
451
|
+
fn scene_value(p: vec2<f32>, c: u32) -> f32 {
|
|
452
|
+
let m = material_at(p);
|
|
453
|
+
if (m != scene_m || c != scene_c) { scene_s = material_signal(m, c); scene_m = m; scene_c = c; }
|
|
454
|
+
return scene_s;
|
|
455
|
+
}
|
|
456
|
+
`;
|
|
457
|
+
/** The full shader: the kernel plus a material module (see `DISPLAY_VIEW_SPEED_KERNEL_WGSL`), and the table adapter unless the module defines `scene_value`. */
|
|
424
458
|
export function assembleDisplayViewSpeedWgsl(materialModuleWgsl) {
|
|
425
|
-
|
|
459
|
+
const adapter = /\bfn scene_value\(/u.test(materialModuleWgsl) ? "" : DISPLAY_VIEW_MATERIAL_SCENE_VALUE_WGSL;
|
|
460
|
+
return DISPLAY_VIEW_SPEED_KERNEL_WGSL + "\n" + materialModuleWgsl + "\n" + adapter;
|
|
426
461
|
}
|
|
427
462
|
//# sourceMappingURL=wgsl-display-view-speed-kernel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wgsl-display-view-speed-kernel.js","sourceRoot":"","sources":["../../src/gpu/wgsl-display-view-speed-kernel.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,CAAC;AAC9C,6GAA6G;AAC7G,MAAM,CAAC,MAAM,wCAAwC,GAAG,CAAC,CAAC;AAC1D,MAAM,CAAC,MAAM,4BAA4B,GAAG,wCAAwC,GAAG,CAAC,CAAC;AACzF,iGAAiG;AACjG,MAAM,CAAC,MAAM,gCAAgC,GAAG,EAAE,CAAC;AACnD,yIAAyI;AACzI,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,CAAC;AAC7C,6IAA6I;AAC7I,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AACzC;;;;GAIG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,CAAC;AAC/C,8DAA8D;AAC9D,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,CAAC;AAC/C,+CAA+C;AAC/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC;IAC5D,yEAAyE;IACzE,OAAO,EAAE,CAAC;IACV,4FAA4F;IAC5F,IAAI,EAAE,EAAE;IACR,2DAA2D;IAC3D,SAAS,EAAE,GAAG;IACd,0DAA0D;IAC1D,aAAa,EAAE,GAAG;IAClB,IAAI,EAAE,GAAG;CACV,CAAC,CAAC;AACH,yEAAyE;AACzE,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAC3C,qIAAqI;AACrI,MAAM,SAAS,GAAG,uBAAuB,CAAC;AAC1C;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAC7C,MAAM,CAAC,MAAM,4BAA4B,GAAG,KAAK,CAAC;AAClD,8GAA8G;AAC9G,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAChD,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAG,CAAC;AAEpD,MAAM,OAAO,GAAG,CAAC,KAAa,EAAU,EAAE;IACxC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACxC,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC;AACjD,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,UAAU,CAAC;iBACxC,SAAS;;;2BAGC,OAAO,CAAC,wBAAwB,CAAC;+BAC7B,OAAO,CAAC,4BAA4B,CAAC;+BACrC,OAAO,CAAC,4BAA4B,CAAC;sBAC9C,4BAA4B;sBAC5B,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCAyHjB,gBAAgB,CAAC,aAAa;;iCAE9B,gBAAgB,CAAC,aAAa,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;;;iBAsBnD,gBAAgB,CAAC,OAAO;;;;;;;;2BAQd,2BAA2B;;uCAEf,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAqE7C,gBAAgB,CAAC,IAAI;;;;;;;;;;;kCAWR,gBAAgB,CAAC,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0DAkEF,gBAAgB,CAAC,SAAS;;;;;;;;;gBASpE,0BAA0B;;;;;;;;;CASzC,CAAC;AAEF,iGAAiG;AACjG,MAAM,UAAU,4BAA4B,CAAC,kBAA0B;IACrE,OAAO,8BAA8B,GAAG,IAAI,GAAG,kBAAkB,GAAG,IAAI,CAAC;AAC3E,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * WGSL kernel of the display view's Speed path on the GPU (#478): one invocation per display pixel of the exact\n * area mean (docs/DISPLAY_VIEW.md, \"Exact area mean\") without diffraction, with the bilinear demosaic and chart\n * materials. It evaluates `renderDisplayView`'s per-sample loop (facade/display-view.ts) for every real pixel of the\n * display pixel's footprint, in the reference's operation order where the order matters, in float32:\n *\n * 1. the real pixels the footprint covers and their overlap weights a_j = w_j / A (the host computes the 1-D overlaps\n * divided by the scale in float64; the kernel multiplies the two axes);\n * 2. for every native site the real pixels' demosaic reads (the footprint plus one site of reach), the expected\n * electrons: the scene material at the pixel aperture's query offsets (the material module, `material_at`), the\n * material's channel signal from a table the host computed in float64 (Σ_λ A_c(λ)·L(λ)), summed over the offsets\n * in the reference's order, plus the dark electrons;\n * 3. the readout moments of each site (mean k·e, variance k²·e + c₀, third cumulant k³·e) and the clip at the white\n * level (the clipped-normal moments, in a cancellation-free standardized form);\n * 4. per real pixel the bilinear kernels, white balance and highlight clip, the colour matrix, the tone curve\n * (identity, or positive Reinhard by the reference's 4 × 16-point Gauss–Legendre rule) and the clip to [0, 1] with\n * the first-order skewness term;\n * 5. the display pixel's expected value Σ_j a_j·E[L_j], the linear (Stein) covariance Σ_c B_c·σ_c²·a_c·a_cᵀ with the\n * closed-form B_c of the footprint, and the independent residual Σ_j a_j²·r_j.\n *\n * It outputs, per display pixel, the three means, the three variances (linear plus residual), the three covariances\n * and two running error terms: the absolute error bound of the mean and of the variance that the clip steps\n * contribute (a fixed formula evaluated from the pixel's own float32 values; docs/WEBGPU.md, \"Display view (Speed)\").\n * #533: it also decides each real pixel's saturation probability where the float32 values leave no doubt: a site is\n * certainly unclipped or certainly clipped when its standardized distance from white, with the site's mean moved by twice\n * `DISPLAY_VIEW_SITE_RELATIVE_U`·E of itself, still exceeds twice the reference's 8.5 (where the reference's probability is\n * exactly 0 or 1), and a real pixel is certainly saturated (P = 1) when a site its demosaic reads is certainly clipped and\n * certainly not (P = 0) when all are certainly unclipped. Three flag words per display pixel: bit 0 of the first the\n * material flag, bit 1 a real pixel left undecided (the host computes the pixel's count with the reference); the other two\n * a bit per real pixel j·nx + i of the footprint with P = 1.\n * The host adds the output quantization term, draws the noise, encodes and rounds (`display-view-speed-gpu.ts`), so\n * the noise draw is the CPU's bit for bit.\n *\n * Precision: float32 with an a-priori bound per step from the WGSL accuracy table (+ − × within one float32 rounding in\n * either direction, E = 2^-23; division 2.5 ULP, sqrt 4.5 ULP, exp 3 + 2|x| ULP; no trigonometric built-in is used). Every quotient that is a constant of\n * the request (the overlaps over the scale, the axis sums over the squared scale, 1/Σw² of the demosaic kernels) is\n * computed on the host in float64 and uploaded. Data-dependent quotients (z = (t − m)/s, the Abramowitz–Stegun t,\n * the skewness) carry the 2.5 ULP bound.\n */\n\nexport const DISPLAY_VIEW_WORKGROUP_SIZE = 64;\n/** Largest footprint per axis (real pixels): the site window is (n + 2)² ≤ 64 entries of private storage. */\nexport const DISPLAY_VIEW_GPU_MAXIMUM_PIXELS_PER_AXIS = 6;\nexport const DISPLAY_VIEW_GPU_WINDOW_SIDE = DISPLAY_VIEW_GPU_MAXIMUM_PIXELS_PER_AXIS + 2;\n/** Largest number of query offsets (pixel-aperture nodes × filter spots) the aux table holds. */\nexport const DISPLAY_VIEW_GPU_MAXIMUM_OFFSETS = 16;\n/** Floats per display pixel in the output buffer: m0 m1 m2, v00 v11 v22 (linear + residual), c01 c02 c12, mean bound, variance bound. */\nexport const DISPLAY_VIEW_OUTPUT_FLOATS = 11;\n/** #533: flag words per display pixel: the flags (bit 0 material uncertain, bit 1 a highlight undecided), then the 36-bit saturated mask. */\nexport const DISPLAY_VIEW_FLAG_WORDS = 3;\n/**\n * #533: relative bound of a site's float32 mean and variance against the reference's float64, in units of E: the electrons'\n * sum of at most 16 offsets (each term a host-rounded weight and table value and one product), the dark electrons, and the\n * readout's products and sum carry at most 26 E; 64 leaves the rest as spare.\n */\nexport const DISPLAY_VIEW_SITE_RELATIVE_U = 64;\n/** Floats per column or row record of the geometry buffer. */\nexport const DISPLAY_VIEW_GEOMETRY_STRIDE = 20;\n/** Layout of the aux table (float32 words). */\nexport const DISPLAY_VIEW_AUX = /* @__PURE__ */ Object.freeze({\n /** Per offset o: ou (0.5 + ox − W/2), ov (0.5 + oy − H/2), weight, 0. */\n offsets: 0,\n /** Per phase p, channel c, tap t: dx, dy, weight, 0 (4 taps; unused taps have weight 0). */\n taps: 64,\n /** Per phase p, channel c: 1 / Σ_t w_t² (host float64). */\n inverseW2: 256,\n /** 16 Gauss–Legendre nodes then 16 weights on [−1, 1]. */\n gaussLegendre: 272,\n size: 304\n});\n/** Uniform parameter words (see `Params` below): 40 words, 160 bytes. */\nexport const DISPLAY_VIEW_PARAM_WORDS = 40;\n/** The `E` of the bounds: one WGSL rounding of + − × in either direction, 2^-23 (W3C WGSL \"Floating Point Accuracy\"; #471, #487). */\nconst E_LITERAL = \"1.1920928955078125e-7\";\n/**\n * Clip-step constants of the running bound, in units of E (docs/WEBGPU.md, \"Display view (Speed)\", derivation): the\n * absolute error of the clipped-normal mean in units of the standard deviation (`CLIP_MEAN_U`) and of its variance in\n * units of the variance (`CLIP_VARIANCE_U`), for one clip side. The host doubles every bound (MARGIN).\n */\nexport const DISPLAY_VIEW_CLIP_MEAN_U = 1400;\nexport const DISPLAY_VIEW_CLIP_VARIANCE_U = 36000;\n/** The additional relative error of the Reinhard quadrature, in units of E, for the mean and the variance. */\nexport const DISPLAY_VIEW_REINHARD_MEAN_U = 256;\nexport const DISPLAY_VIEW_REINHARD_VARIANCE_U = 512;\n\nconst literal = (value: number): string => {\n const text = String(Math.fround(value));\n return /[.e]/u.test(text) ? text : `${text}.0`;\n};\n\n/**\n * The kernel's own WGSL, without the material module. `assembleDisplayViewSpeedWgsl` appends a module that defines\n * `fn material_at(p: vec2<f32>) -> u32` and `var<private> material_uncertain: bool` (set to true when the point's\n * classification is within its bound of a material boundary; the kernel then flags the display pixel for host\n * recomputation). The module may declare bindings in @group(1) and use the constants E and SLACK declared here.\n */\nexport const DISPLAY_VIEW_SPEED_KERNEL_WGSL = /* wgsl */ `\nconst E: f32 = ${E_LITERAL};\nconst SLACK: f32 = 1e-14;\nconst CLIP_REACH: f32 = 8.5;\nconst CLIP_MEAN_U: f32 = ${literal(DISPLAY_VIEW_CLIP_MEAN_U)};\nconst CLIP_VARIANCE_U: f32 = ${literal(DISPLAY_VIEW_CLIP_VARIANCE_U)};\nconst SITE_RELATIVE_U: f32 = ${literal(DISPLAY_VIEW_SITE_RELATIVE_U)};\nconst WINDOW: u32 = ${DISPLAY_VIEW_GPU_WINDOW_SIDE}u;\nconst STRIDE: u32 = ${DISPLAY_VIEW_GEOMETRY_STRIDE}u;\nstruct Params {\n count: u32, row0: u32, region_w: u32, region_x: u32,\n region_y: u32, margin: u32, native_w: u32, native_h: u32,\n columns: u32, tone: u32, offsets: u32, pad0: u32,\n k0: f32, k1: f32, k2: f32, reach2: f32,\n dark0: f32, dark1: f32, dark2: f32, clip_level: f32,\n c0_0: f32, c0_1: f32, c0_2: f32, pad1: f32,\n g0: f32, g1: f32, g2: f32, pad2: f32,\n m00: f32, m01: f32, m02: f32, m10: f32,\n m11: f32, m12: f32, m20: f32, m21: f32,\n m22: f32, scale_u: f32, scale_v: f32, pad3: f32,\n};\n@group(0) @binding(0) var<uniform> params: Params;\n@group(0) @binding(1) var<storage, read> aux: array<f32>;\n@group(0) @binding(2) var<storage, read> geometry: array<f32>;\n@group(0) @binding(3) var<storage, read> site_table: array<f32>;\n@group(0) @binding(4) var<storage, read_write> out: array<f32>;\n@group(0) @binding(5) var<storage, read_write> flags: array<u32>;\n\nvar<private> site_mean: array<f32, 64>;\nvar<private> site_var: array<f32, 64>;\nvar<private> site_third: array<f32, 64>;\nvar<private> site_bound: array<f32, 64>;\n// #533: 0 certainly below white, 1 certainly at or above it, 2 undecided.\nvar<private> site_clip: array<u32, 64>;\n\nfn k_of(c: u32) -> f32 { if (c == 0u) { return params.k0; } if (c == 1u) { return params.k1; } return params.k2; }\nfn dark_of(c: u32) -> f32 { if (c == 0u) { return params.dark0; } if (c == 1u) { return params.dark1; } return params.dark2; }\nfn c0_of(c: u32) -> f32 { if (c == 0u) { return params.c0_0; } if (c == 1u) { return params.c0_1; } return params.c0_2; }\nfn g_of(c: u32) -> f32 { if (c == 0u) { return params.g0; } if (c == 1u) { return params.g1; } return params.g2; }\nfn m_of(r: u32, c: u32) -> f32 {\n let i = r * 3u + c;\n switch (i) {\n case 0u: { return params.m00; } case 1u: { return params.m01; } case 2u: { return params.m02; }\n case 3u: { return params.m10; } case 4u: { return params.m11; } case 5u: { return params.m12; }\n case 6u: { return params.m20; } case 7u: { return params.m21; } default: { return params.m22; }\n }\n}\n// Standard normal density, as the reference forms it: 0.3989422804014327·exp(−0.5·z·z).\nfn phi(z: f32) -> f32 { return 0.3989422804014327 * exp(-0.5 * z * z); }\n// Abramowitz & Stegun 26.2.17: returns (Φ(z), 1 − Φ(z)), each formed from the tail q directly where it is small.\nfn pq(z: f32) -> vec2<f32> {\n let x = abs(z);\n let t = 1.0 / (1.0 + 0.2316419 * x);\n let q = phi(x) * t * (0.319381530 + t * (-0.356563782 + t * (1.781477937 + t * (-1.821255978 + t * 1.330274429))));\n if (z >= 0.0) { return vec2<f32>(1.0 - q, q); }\n return vec2<f32>(q, 1.0 - q);\n}\n// #533: whether a site with mean m (bound dm) and variance v (bound dv) is certainly below white (0), certainly at or above it\n// (1) or undecided (2): the reference's clip probability is exactly 0 or 1 beyond 8.5 standard deviations, and the decision here\n// asks for twice that distance (4·reach²) after moving the mean by twice its bound and the variance up by twice its bound.\nfn clip_state(m: f32, dm: f32, v: f32, dv: f32) -> u32 {\n let gap = 1.0 - m;\n let wide = 4.0 * params.reach2 * (v + 2.0 * dv);\n let below = gap - 2.0 * dm;\n let above = gap + 2.0 * dm;\n if (below > 0.0 && below * below > wide) { return 0u; }\n if (above < 0.0 && above * above > wide) { return 1u; }\n return 2u;\n}\n// Moments of min(Y, top) for Y ~ N(m, v): (mean, variance, slope P). The variance is v·(P − zφ + z²Q − δ²) with\n// δ = φ − zQ: algebraically E[min²] − E[min]² without the m² cancellation.\nfn upper_clip(m: f32, v: f32, top: f32) -> vec3<f32> {\n if (!(v > 0.0)) { return vec3<f32>(min(m, top), 0.0, select(0.0, 1.0, m < top)); }\n let s = sqrt(v);\n let z = (top - m) / s;\n if (z > CLIP_REACH) { return vec3<f32>(m, v, 1.0); }\n if (z < -CLIP_REACH) { return vec3<f32>(top, 0.0, 0.0); }\n let p = pq(z);\n let d = phi(z);\n let delta = d - z * p.y;\n let mean = m - s * delta;\n let ratio = p.x - z * d + z * z * p.y - delta * delta;\n return vec3<f32>(mean, v * max(0.0, ratio), p.x);\n}\n// Moments of clip(Y, 0, 1) for Y with mean m, variance v and standardized skewness γ (|γ| ≤ 1): (mean, variance, inside).\n// With Z standard normal, W = m + s·g(Z), g = clip(Z, a, b): E[g] = aΦa + φa − φb + bQb, E[g²] = a²Φa + (Φb − Φa) −\n// (bφb − aφa) + b²Qb; the mean adds the reference's Edgeworth term (s·γ/6)·(aφa − bφb).\nfn unit_clip(m: f32, v: f32, skewness: f32) -> vec3<f32> {\n if (!(v > 0.0)) { return vec3<f32>(clamp(m, 0.0, 1.0), 0.0, select(0.0, 1.0, m > 0.0 && m < 1.0)); }\n let s = sqrt(v);\n let a = -m / s;\n let b = (1.0 - m) / s;\n if (a < -CLIP_REACH && b > CLIP_REACH) { return vec3<f32>(m, v, 1.0); }\n var pa = 0.0; var da = 0.0;\n if (!(a < -CLIP_REACH)) { pa = pq(a).x; da = phi(a); }\n var pb = 1.0; var qb = 0.0; var db = 0.0;\n if (!(b > CLIP_REACH)) { let p = pq(b); pb = p.x; qb = p.y; db = phi(b); }\n let inside = pb - pa;\n let gamma = clamp(skewness, -1.0, 1.0);\n let aa = a * da;\n let bb = b * db;\n let eg = a * pa + (da - db) + b * qb;\n let eg2 = a * a * pa + inside - (bb - aa) + b * b * qb;\n let normal_mean = m + s * eg;\n var mean = normal_mean;\n var skew_shift = 0.0;\n if (gamma != 0.0) { skew_shift = s * gamma / 6.0 * (aa - bb); mean = normal_mean + skew_shift; }\n // The reference forms E[Y²] − (E[Y] + shift)², so the shift also enters its variance: −shift·(2·E[Y] + shift).\n return vec3<f32>(mean, max(0.0, v * (eg2 - eg * eg) - skew_shift * (2.0 * normal_mean + skew_shift)), inside);\n}\n// Positive Reinhard per channel then the clip to [0, 1]: h(x) = x/(1 + x) for x > 0, else 0. Composite 16-point\n// Gauss–Legendre over [max(0, m − 8.5s), m + 8.5s] in 4 panels, as the reference; the variance is formed about h(m).\nfn reinhard_moments(m: f32, v: f32) -> vec3<f32> {\n if (!(v > 0.0)) {\n if (m > 0.0) { return vec3<f32>(m / (1.0 + m), 0.0, 1.0 / ((1.0 + m) * (1.0 + m))); }\n return vec3<f32>(0.0, 0.0, 0.0);\n }\n let s = sqrt(v);\n // The reference's panels [max(0, m − 8.5s), m + 8.5s] in standardized units z = (x − m)/s, so the node's z is formed\n // without the cancellation x − m: zlo = max(−m/s, −8.5), weight = zhalf·w_k·φ(z_k) (= half·w_k·φ((x − m)/s)/s), x = m + s·z.\n let zlo = max(-m / s, -CLIP_REACH);\n if (!(CLIP_REACH > zlo)) { return vec3<f32>(0.0, 0.0, 0.0); }\n let hm = select(0.0, m / (1.0 + m), m > 0.0);\n var e1 = 0.0; var e2 = 0.0; var ed = 0.0;\n let zwidth = (CLIP_REACH - zlo) / 4.0;\n for (var p = 0u; p < 4u; p = p + 1u) {\n let zc = zlo + (f32(p) + 0.5) * zwidth;\n let zhalf = zwidth / 2.0;\n for (var k = 0u; k < 16u; k = k + 1u) {\n let z = zc + zhalf * aux[${DISPLAY_VIEW_AUX.gaussLegendre}u + k];\n let x = m + s * z;\n let weight = zhalf * aux[${DISPLAY_VIEW_AUX.gaussLegendre + 16}u + k] * phi(z);\n let h = x / (1.0 + x);\n e1 = e1 + weight * h;\n e2 = e2 + weight * (h - hm) * (h - hm);\n ed = ed + weight / ((1.0 + x) * (1.0 + x));\n }\n }\n let shifted = e1 - hm;\n return vec3<f32>(e1, max(0.0, e2 - shifted * shifted), ed);\n}\nfn reflect_x(x: i32) -> i32 { if (x < 0) { return -x; } if (x >= i32(params.native_w)) { return 2 * i32(params.native_w) - 2 - x; } return x; }\nfn reflect_y(y: i32) -> i32 { if (y < 0) { return -y; } if (y >= i32(params.native_h)) { return 2 * i32(params.native_h) - 2 - y; } return y; }\nfn channel_of(x: i32, y: i32) -> u32 {\n if ((y & 1) == 0) { return select(1u, 0u, (x & 1) == 0); }\n return select(2u, 1u, (x & 1) == 0);\n}\n// The expected photo electrons of native site (x, y): Σ_o w_o·table[m_o, c] in offset order (directSite).\nfn site_electrons(x: i32, y: i32, c: u32) -> f32 {\n var sum = 0.0;\n let fx = f32(x);\n let fy = f32(y);\n for (var o = 0u; o < params.offsets; o = o + 1u) {\n let base = ${DISPLAY_VIEW_AUX.offsets}u + 4u * o;\n let u = (fx + aux[base]) * params.scale_u;\n let v = (fy + aux[base + 1u]) * params.scale_v;\n let m = material_at(vec2<f32>(u, v));\n sum = sum + aux[base + 2u] * site_table[m * 3u + c];\n }\n return sum;\n}\n@compute @workgroup_size(${DISPLAY_VIEW_WORKGROUP_SIZE})\nfn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) groups: vec3<u32>) {\n let i = gid.x + gid.y * groups.x * ${DISPLAY_VIEW_WORKGROUP_SIZE}u;\n if (i >= params.count) { return; }\n material_uncertain = false;\n let rx = i % params.region_w;\n let ry = params.row0 + i / params.region_w;\n let col = rx * STRIDE;\n let row = (params.columns + ry) * STRIDE;\n let col_first = bitcast<i32>(geometry[col]);\n let nx = bitcast<u32>(geometry[col + 1u]);\n let row_first = bitcast<i32>(geometry[row]);\n let ny = bitcast<u32>(geometry[row + 1u]);\n let margin = i32(params.margin);\n // 2. and 3.: the sites of the footprint plus one site of reach, once each.\n let x0 = col_first + margin - 1;\n let y0 = row_first + margin - 1;\n let window_w = nx + 2u;\n for (var sj = 0u; sj < ny + 2u; sj = sj + 1u) {\n let sy = reflect_y(y0 + i32(sj));\n for (var si = 0u; si < window_w; si = si + 1u) {\n let sx = reflect_x(x0 + i32(si));\n let c = channel_of(sx, sy);\n let e = site_electrons(sx, sy, c) + dark_of(c);\n let kc = k_of(c);\n let mean = kc * e;\n let variance = kc * kc * e + c0_of(c);\n let gap = 1.0 - mean;\n let slot = sj * window_w + si;\n site_third[slot] = kc * kc * kc * e;\n site_clip[slot] = clip_state(mean, SITE_RELATIVE_U * E * mean, variance, SITE_RELATIVE_U * E * variance);\n if (gap > 0.0 && gap * gap > params.reach2 * variance) {\n site_mean[slot] = mean; site_var[slot] = variance; site_bound[slot] = 0.0;\n } else {\n let clipped = upper_clip(mean, variance, 1.0);\n site_mean[slot] = clipped.x; site_var[slot] = clipped.y; site_bound[slot] = sqrt(variance);\n }\n }\n }\n // B_c of the footprint from the host's axis sums (each over its scale squared): red, green, blue.\n let xb_even = geometry[col + 8u]; let xb_odd = geometry[col + 9u];\n let xpp_even = geometry[col + 10u]; let xpp_odd = geometry[col + 11u];\n let xqq_even = geometry[col + 12u]; let xqq_odd = geometry[col + 13u];\n let xpq_even = geometry[col + 14u]; let xpq_odd = geometry[col + 15u];\n let yb_even = geometry[row + 8u]; let yb_odd = geometry[row + 9u];\n let ypp_even = geometry[row + 10u]; let ypp_odd = geometry[row + 11u];\n let yqq_even = geometry[row + 12u]; let yqq_odd = geometry[row + 13u];\n let ypq_even = geometry[row + 14u]; let ypq_odd = geometry[row + 15u];\n let b0 = xb_even * yb_even;\n let b1 = (xpp_odd * ypp_even + xqq_odd * ypp_even + xpp_odd * yqq_even + 2.0 * xpq_odd * ypp_even + 2.0 * xpp_odd * ypq_even + 2.0 * xpq_odd * ypq_even) +\n (xpp_even * ypp_odd + xqq_even * ypp_odd + xpp_even * yqq_odd + 2.0 * xpq_even * ypp_odd + 2.0 * xpp_even * ypq_odd + 2.0 * xpq_even * ypq_odd);\n let b2 = xb_odd * yb_odd;\n let reinhard = params.tone == 1u;\n var s0 = 0.0; var s1 = 0.0; var s2 = 0.0;\n var c00 = 0.0; var c01 = 0.0; var c02 = 0.0; var c11 = 0.0; var c12 = 0.0; var c22 = 0.0;\n var r0 = 0.0; var r1 = 0.0; var r2 = 0.0;\n var bound_mean = 0.0; var bound_var = 0.0;\n // #533: the saturated real pixels (bit j·nx + i) and whether any real pixel is undecided.\n var mask0 = 0u; var mask1 = 0u; var undecided = false;\n // 4. and 5.: every real pixel of the footprint with its overlap weight.\n for (var j = 0u; j < ny; j = j + 1u) {\n let ay = geometry[row + 2u + j];\n for (var ii = 0u; ii < nx; ii = ii + 1u) {\n let aj = geometry[col + 2u + ii] * ay;\n let x = col_first + i32(ii) + margin;\n let y = row_first + i32(j) + margin;\n let phase = u32(y & 1) * 2u + u32(x & 1);\n var cm: array<f32, 3>; var cvv: array<f32, 3>; var cth: array<f32, 3>; var csv: array<f32, 3>; var cb: array<f32, 3>;\n var clipped = false; var near_white = false;\n for (var c = 0u; c < 3u; c = c + 1u) {\n var mean = 0.0; var variance = 0.0; var third = 0.0; var bnd = 0.0;\n let taps = ${DISPLAY_VIEW_AUX.taps}u + (phase * 3u + c) * 16u;\n for (var t = 0u; t < 4u; t = t + 1u) {\n let w = aux[taps + 4u * t + 2u];\n let slot = u32((i32(j) + 1 + i32(aux[taps + 4u * t + 1u])) * i32(window_w) + i32(ii) + 1 + i32(aux[taps + 4u * t]));\n mean = mean + w * site_mean[slot];\n variance = variance + w * w * site_var[slot];\n third = third + w * w * w * site_third[slot];\n bnd = max(bnd, select(0.0, site_bound[slot], w != 0.0));\n if (w != 0.0) { if (site_clip[slot] == 1u) { clipped = true; } else if (site_clip[slot] == 2u) { near_white = true; } }\n }\n cm[c] = mean; cvv[c] = variance; cth[c] = third; cb[c] = bnd;\n csv[c] = variance * aux[${DISPLAY_VIEW_AUX.inverseW2}u + phase * 3u + c];\n }\n if (clipped) {\n let bit = j * nx + ii;\n if (bit < 32u) { mask0 = mask0 | (1u << bit); } else { mask1 = mask1 | (1u << (bit - 32u)); }\n } else if (near_white) { undecided = true; }\n // White balance and the highlight clip at the smallest gain: bm, bv, bs (slope), with the clip's bound terms.\n var bm: array<f32, 3>; var bv: array<f32, 3>; var bs: array<f32, 3>; var bbm: array<f32, 3>; var bbv: array<f32, 3>;\n for (var c = 0u; c < 3u; c = c + 1u) {\n let gc = g_of(c);\n let um = gc * cm[c];\n let uv = gc * gc * cvv[c];\n let gap = params.clip_level - um;\n bbm[c] = gc * CLIP_MEAN_U * cb[c];\n bbv[c] = gc * gc * CLIP_VARIANCE_U * cb[c] * cb[c];\n if (gap > 0.0 && gap * gap > params.reach2 * uv) { bm[c] = um; bv[c] = uv; bs[c] = gc; }\n else {\n let clipped = upper_clip(um, uv, params.clip_level);\n bm[c] = clipped.x; bv[c] = clipped.y; bs[c] = gc * clipped.z;\n bbm[c] = bbm[c] + CLIP_MEAN_U * sqrt(uv);\n bbv[c] = bbv[c] + CLIP_VARIANCE_U * uv;\n }\n }\n // Colour matrix, then the rendering of each component (tone curve, clip to [0, 1]).\n var hm: array<f32, 3>; var hv: array<f32, 3>; var hs: array<f32, 3>; var hbm: array<f32, 3>; var hbv: array<f32, 3>;\n for (var comp = 0u; comp < 3u; comp = comp + 1u) {\n let r0m = m_of(comp, 0u); let r1m = m_of(comp, 1u); let r2m = m_of(comp, 2u);\n let mean = r0m * bm[0] + r1m * bm[1] + r2m * bm[2];\n let variance = r0m * r0m * bv[0] + r1m * r1m * bv[1] + r2m * r2m * bv[2];\n var bm_c = abs(r0m) * bbm[0] + abs(r1m) * bbm[1] + abs(r2m) * bbm[2];\n var bv_c = r0m * r0m * bbv[0] + r1m * r1m * bbv[1] + r2m * r2m * bbv[2];\n if (!reinhard && mean > 0.0 && mean < 1.0 && mean * mean > params.reach2 * variance && (1.0 - mean) * (1.0 - mean) > params.reach2 * variance) {\n hm[comp] = mean; hv[comp] = variance; hs[comp] = 1.0;\n } else if (reinhard) {\n let moments = reinhard_moments(mean, variance);\n hm[comp] = moments.x; hv[comp] = moments.y; hs[comp] = moments.z;\n bm_c = bm_c + 2.0 * CLIP_MEAN_U * sqrt(variance);\n bv_c = bv_c + 2.0 * CLIP_VARIANCE_U * variance;\n } else {\n // κ₃ of the component: Σ_c (M_comp,c·Γ_c)³·Σ_t w_t³·κ₃(site) (the sites of one channel share the coefficient).\n let k0 = r0m * bs[0]; let k1 = r1m * bs[1]; let k2 = r2m * bs[2];\n let third = k0 * k0 * k0 * cth[0] + k1 * k1 * k1 * cth[1] + k2 * k2 * k2 * cth[2];\n let skew = select(0.0, third / (variance * sqrt(variance)), variance > 0.0);\n let moments = unit_clip(mean, variance, skew);\n hm[comp] = moments.x; hv[comp] = moments.y; hs[comp] = moments.z;\n bm_c = bm_c + 2.0 * CLIP_MEAN_U * sqrt(variance);\n bv_c = bv_c + 2.0 * CLIP_VARIANCE_U * variance;\n }\n hbm[comp] = bm_c; hbv[comp] = bv_c;\n }\n s0 = s0 + aj * hm[0]; s1 = s1 + aj * hm[1]; s2 = s2 + aj * hm[2];\n // Linear (Stein) part with B_c·σ_c², and the pixel's own linear variance for the residual.\n var l0 = 0.0; var l1 = 0.0; var l2 = 0.0;\n var lb0 = 0.0; var lb1 = 0.0; var lb2 = 0.0;\n for (var c = 0u; c < 3u; c = c + 1u) {\n let a0 = hs[0] * m_of(0u, c) * bs[c];\n let a1 = hs[1] * m_of(1u, c) * bs[c];\n let a2 = hs[2] * m_of(2u, c) * bs[c];\n var bc = b0; if (c == 1u) { bc = b1; } if (c == 2u) { bc = b2; }\n let wgt = aj * bc * csv[c];\n c00 = c00 + wgt * a0 * a0; c01 = c01 + wgt * a0 * a1; c02 = c02 + wgt * a0 * a2;\n c11 = c11 + wgt * a1 * a1; c12 = c12 + wgt * a1 * a2; c22 = c22 + wgt * a2 * a2;\n l0 = l0 + a0 * a0 * cvv[c]; l1 = l1 + a1 * a1 * cvv[c]; l2 = l2 + a2 * a2 * cvv[c];\n // The clip bound of each channel's variance enters the covariance through a_j·B_c·(Δσ_c²/Σw²)·a_i·a_j and the\n // residual's linear prediction through a²·Δσ_c².\n lb0 = lb0 + (a0 * a0) * bbv[c]; lb1 = lb1 + (a1 * a1) * bbv[c]; lb2 = lb2 + (a2 * a2) * bbv[c];\n bound_var = bound_var + aj * bc * (bbv[c] * aux[${DISPLAY_VIEW_AUX.inverseW2}u + phase * 3u + c]) * max(a0 * a0, max(a1 * a1, a2 * a2));\n }\n r0 = r0 + aj * aj * max(0.0, hv[0] - l0);\n r1 = r1 + aj * aj * max(0.0, hv[1] - l1);\n r2 = r2 + aj * aj * max(0.0, hv[2] - l2);\n bound_mean = bound_mean + aj * max(hbm[0], max(hbm[1], hbm[2]));\n bound_var = bound_var + aj * aj * (max(hbv[0], max(hbv[1], hbv[2])) + max(lb0, max(lb1, lb2)));\n }\n }\n let o = i * ${DISPLAY_VIEW_OUTPUT_FLOATS}u;\n out[o] = s0; out[o + 1u] = s1; out[o + 2u] = s2;\n out[o + 3u] = c00 + r0; out[o + 4u] = c11 + r1; out[o + 5u] = c22 + r2;\n out[o + 6u] = c01; out[o + 7u] = c02; out[o + 8u] = c12;\n out[o + 9u] = bound_mean * E; out[o + 10u] = bound_var * E;\n flags[3u * i] = select(0u, 1u, material_uncertain) | select(0u, 2u, undecided);\n flags[3u * i + 1u] = mask0;\n flags[3u * i + 2u] = mask1;\n}\n`;\n\n/** The full shader: the kernel plus a material module (see `DISPLAY_VIEW_SPEED_KERNEL_WGSL`). */\nexport function assembleDisplayViewSpeedWgsl(materialModuleWgsl: string): string {\n return DISPLAY_VIEW_SPEED_KERNEL_WGSL + \"\\n\" + materialModuleWgsl + \"\\n\";\n}\n"]}
|
|
1
|
+
{"version":3,"file":"wgsl-display-view-speed-kernel.js","sourceRoot":"","sources":["../../src/gpu/wgsl-display-view-speed-kernel.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * WGSL kernel of the display view's Speed path on the GPU (#478): one invocation per display pixel of the exact\n * area mean (docs/DISPLAY_VIEW.md, \"Exact area mean\") without diffraction, with the bilinear demosaic and chart\n * materials. It evaluates `renderDisplayView`'s per-sample loop (facade/display-view.ts) for every real pixel of the\n * display pixel's footprint, in the reference's operation order where the order matters, in float32:\n *\n * 1. the real pixels the footprint covers and their overlap weights a_j = w_j / A (the host computes the 1-D overlaps\n * divided by the scale in float64; the kernel multiplies the two axes);\n * 2. for every native site the real pixels' demosaic reads (the footprint plus one site of reach), the expected\n * electrons: the scene material at the pixel aperture's query offsets (the material module, `material_at`), the\n * material's channel signal integrated in the kernel from its spectrum (Σ_λ A_c(λ)·L(λ), `material_signal`), or (#581) the image-plane\n * module's channel signal at the point (`scene_value`), summed over the offsets in the reference's order, plus the dark\n * electrons;\n * 3. the readout moments of each site (mean k·e, variance k²·e + c₀, third cumulant k³·e) and the clip at the white\n * level (the clipped-normal moments, in a cancellation-free standardized form);\n * 4. per real pixel the bilinear kernels, white balance and highlight clip, the colour matrix, the tone curve\n * (identity, or positive Reinhard by the reference's 4 × 16-point Gauss–Legendre rule) and the clip to [0, 1] with\n * the first-order skewness term;\n * 5. the display pixel's expected value Σ_j a_j·E[L_j], the linear (Stein) covariance Σ_c B_c·σ_c²·a_c·a_cᵀ with the\n * closed-form B_c of the footprint, and the independent residual Σ_j a_j²·r_j.\n *\n * It outputs, per display pixel, the three means, the three variances (linear plus residual), the three covariances\n * and two running error terms: the absolute error bound of the mean and of the variance that the clip steps\n * contribute (a fixed formula evaluated from the pixel's own float32 values; docs/WEBGPU.md, \"Display view (Speed)\").\n * #533: it also decides each real pixel's saturation probability where the float32 values leave no doubt: a site is\n * certainly unclipped or certainly clipped when its standardized distance from white, with the site's mean moved by twice\n * `DISPLAY_VIEW_SITE_RELATIVE_U`·E of itself, still exceeds twice the reference's 8.5 (where the reference's probability is\n * exactly 0 or 1), and a real pixel is certainly saturated (P = 1) when a site its demosaic reads is certainly clipped and\n * certainly not (P = 0) when all are certainly unclipped. Three flag words per display pixel: bit 0 of the first the\n * material flag, bit 1 a real pixel left undecided (the host computes the pixel's count with the reference); the other two\n * a bit per real pixel j·nx + i of the footprint with P = 1.\n * The host adds the output quantization term, draws the noise, encodes and rounds (`display-view-speed-gpu.ts`), so\n * the noise draw is the CPU's bit for bit.\n *\n * Precision: float32 with an a-priori bound per step from the WGSL accuracy table (+ − × within one float32 rounding in\n * either direction, E = 2^-23; division 2.5 ULP, sqrt 4.5 ULP, exp 3 + 2|x| ULP; no trigonometric built-in is used). Every quotient that is a constant of\n * the request (the overlaps over the scale, the axis sums over the squared scale, 1/Σw² of the demosaic kernels) is\n * computed on the host in float64 and uploaded. Data-dependent quotients (z = (t − m)/s, the Abramowitz–Stegun t,\n * the skewness) carry the 2.5 ULP bound.\n */\n\nexport const DISPLAY_VIEW_WORKGROUP_SIZE = 64;\n/** Largest footprint per axis (real pixels): the site window is (n + 2)² ≤ 64 entries of private storage. */\nexport const DISPLAY_VIEW_GPU_MAXIMUM_PIXELS_PER_AXIS = 6;\nexport const DISPLAY_VIEW_GPU_WINDOW_SIDE = DISPLAY_VIEW_GPU_MAXIMUM_PIXELS_PER_AXIS + 2;\n/** Largest number of query offsets (pixel-aperture nodes × filter spots) the aux table holds. */\nexport const DISPLAY_VIEW_GPU_MAXIMUM_OFFSETS = 16;\n/** Floats per display pixel in the output buffer: m0 m1 m2, v00 v11 v22 (linear + residual), c01 c02 c12, mean bound, variance bound. */\nexport const DISPLAY_VIEW_OUTPUT_FLOATS = 11;\n/** #533: flag words per display pixel: the flags (bit 0 material uncertain, bit 1 a highlight undecided), then the 36-bit saturated mask. */\nexport const DISPLAY_VIEW_FLAG_WORDS = 3;\n/**\n * #533: relative bound of a site's float32 mean and variance against the reference's float64, in units of E: the electrons'\n * sum of at most 16 offsets (each term a host-rounded weight and a material signal and one product), the dark electrons, and\n * the readout's products and sum carry at most 26 E with a host-rounded material signal (E/2). 2.21.0: the kernel integrates\n * the material signal Σ_n A_c(λ_n)·L_m(λ_n) itself from the host-rounded response and spectrum: each non-negative product\n * carries E/2 + E/2 for its operands and E for its rounding, and the products are summed in blocks of 16 nodes (at most 15\n * additions within a block and 16 across blocks for N ≤ 256 nodes): 33 E instead of E/2, so a site carries at most 58.5 E,\n * inside the unchanged 64.\n */\nexport const DISPLAY_VIEW_SITE_RELATIVE_U = 64;\n/** Most spectral nodes the Speed kernel integrates per site (DISPLAY_VIEW_SITE_RELATIVE_U: 16 blocks of 16). */\nexport const DISPLAY_VIEW_SPEED_MAXIMUM_NODES = 256;\n/** Floats per column or row record of the geometry buffer. */\nexport const DISPLAY_VIEW_GEOMETRY_STRIDE = 20;\n/** Layout of the aux table (float32 words). */\nexport const DISPLAY_VIEW_AUX = /* @__PURE__ */ Object.freeze({\n /** Per offset o: ou (0.5 + ox − W/2), ov (0.5 + oy − H/2), weight, 0. */\n offsets: 0,\n /** Per phase p, channel c, tap t: dx, dy, weight, 0 (4 taps; unused taps have weight 0). */\n taps: 64,\n /** Per phase p, channel c: 1 / Σ_t w_t² (host float64). */\n inverseW2: 256,\n /** 16 Gauss–Legendre nodes then 16 weights on [−1, 1]. */\n gaussLegendre: 272,\n size: 304\n});\n/** Uniform parameter words (see `Params` below): 40 words, 160 bytes. */\nexport const DISPLAY_VIEW_PARAM_WORDS = 40;\n/** The `E` of the bounds: one WGSL rounding of + − × in either direction, 2^-23 (W3C WGSL \"Floating Point Accuracy\"; #471, #487). */\nconst E_LITERAL = \"1.1920928955078125e-7\";\n/**\n * Clip-step constants of the running bound, in units of E (docs/WEBGPU.md, \"Display view (Speed)\", derivation): the\n * absolute error of the clipped-normal mean in units of the standard deviation (`CLIP_MEAN_U`) and of its variance in\n * units of the variance (`CLIP_VARIANCE_U`), for one clip side. The host doubles every bound (MARGIN).\n */\nexport const DISPLAY_VIEW_CLIP_MEAN_U = 1400;\nexport const DISPLAY_VIEW_CLIP_VARIANCE_U = 36000;\n/** The additional relative error of the Reinhard quadrature, in units of E, for the mean and the variance. */\nexport const DISPLAY_VIEW_REINHARD_MEAN_U = 256;\nexport const DISPLAY_VIEW_REINHARD_VARIANCE_U = 512;\n\nconst literal = (value: number): string => {\n const text = String(Math.fround(value));\n return /[.e]/u.test(text) ? text : `${text}.0`;\n};\n\n/**\n * The kernel's own WGSL, without the material module. `assembleDisplayViewSpeedWgsl` appends a module that defines\n * `fn material_at(p: vec2<f32>) -> u32` and `var<private> material_uncertain: bool` (set to true when the point's\n * classification is within its bound of a material boundary; the kernel then flags the display pixel for host\n * recomputation), and the adapter `scene_value(p, c) = material_signal(material_at(p), c)`. #581: a module may instead define\n * `fn scene_value(p: vec2<f32>, c: u32) -> f32` itself (the image-plane module: the print's channel signal at p) and then\n * declares how many roundings it adds (`DisplayViewGpuMaterialModule.extraSiteRoundings`). The module may declare bindings\n * in @group(1) and use the constants E and SLACK declared here.\n */\nexport const DISPLAY_VIEW_SPEED_KERNEL_WGSL = /* wgsl */ `\nconst E: f32 = ${E_LITERAL};\nconst SLACK: f32 = 1e-14;\nconst CLIP_REACH: f32 = 8.5;\nconst CLIP_MEAN_U: f32 = ${literal(DISPLAY_VIEW_CLIP_MEAN_U)};\nconst CLIP_VARIANCE_U: f32 = ${literal(DISPLAY_VIEW_CLIP_VARIANCE_U)};\nconst SITE_RELATIVE_U: f32 = ${literal(DISPLAY_VIEW_SITE_RELATIVE_U)};\nconst WINDOW: u32 = ${DISPLAY_VIEW_GPU_WINDOW_SIDE}u;\nconst STRIDE: u32 = ${DISPLAY_VIEW_GEOMETRY_STRIDE}u;\nstruct Params {\n count: u32, row0: u32, region_w: u32, region_x: u32,\n region_y: u32, margin: u32, native_w: u32, native_h: u32,\n columns: u32, tone: u32, offsets: u32, nodes: u32,\n k0: f32, k1: f32, k2: f32, reach2: f32,\n dark0: f32, dark1: f32, dark2: f32, clip_level: f32,\n c0_0: f32, c0_1: f32, c0_2: f32, pad1: f32,\n g0: f32, g1: f32, g2: f32, pad2: f32,\n m00: f32, m01: f32, m02: f32, m10: f32,\n m11: f32, m12: f32, m20: f32, m21: f32,\n m22: f32, scale_u: f32, scale_v: f32, pad3: f32,\n};\n@group(0) @binding(0) var<uniform> params: Params;\n@group(0) @binding(1) var<storage, read> aux: array<f32>;\n@group(0) @binding(2) var<storage, read> geometry: array<f32>;\n@group(0) @binding(3) var<storage, read> spectral_table: array<f32>;\n@group(0) @binding(4) var<storage, read_write> out: array<f32>;\n@group(0) @binding(5) var<storage, read_write> flags: array<u32>;\n\nvar<private> site_mean: array<f32, 64>;\nvar<private> site_var: array<f32, 64>;\nvar<private> site_third: array<f32, 64>;\nvar<private> site_bound: array<f32, 64>;\n// #533: 0 certainly below white, 1 certainly at or above it, 2 undecided.\nvar<private> site_clip: array<u32, 64>;\n\nfn k_of(c: u32) -> f32 { if (c == 0u) { return params.k0; } if (c == 1u) { return params.k1; } return params.k2; }\nfn dark_of(c: u32) -> f32 { if (c == 0u) { return params.dark0; } if (c == 1u) { return params.dark1; } return params.dark2; }\nfn c0_of(c: u32) -> f32 { if (c == 0u) { return params.c0_0; } if (c == 1u) { return params.c0_1; } return params.c0_2; }\nfn g_of(c: u32) -> f32 { if (c == 0u) { return params.g0; } if (c == 1u) { return params.g1; } return params.g2; }\nfn m_of(r: u32, c: u32) -> f32 {\n let i = r * 3u + c;\n switch (i) {\n case 0u: { return params.m00; } case 1u: { return params.m01; } case 2u: { return params.m02; }\n case 3u: { return params.m10; } case 4u: { return params.m11; } case 5u: { return params.m12; }\n case 6u: { return params.m20; } case 7u: { return params.m21; } default: { return params.m22; }\n }\n}\n// Standard normal density, as the reference forms it: 0.3989422804014327·exp(−0.5·z·z).\nfn phi(z: f32) -> f32 { return 0.3989422804014327 * exp(-0.5 * z * z); }\n// Abramowitz & Stegun 26.2.17: returns (Φ(z), 1 − Φ(z)), each formed from the tail q directly where it is small.\nfn pq(z: f32) -> vec2<f32> {\n let x = abs(z);\n let t = 1.0 / (1.0 + 0.2316419 * x);\n let q = phi(x) * t * (0.319381530 + t * (-0.356563782 + t * (1.781477937 + t * (-1.821255978 + t * 1.330274429))));\n if (z >= 0.0) { return vec2<f32>(1.0 - q, q); }\n return vec2<f32>(q, 1.0 - q);\n}\n// #533: whether a site with mean m (bound dm) and variance v (bound dv) is certainly below white (0), certainly at or above it\n// (1) or undecided (2): the reference's clip probability is exactly 0 or 1 beyond 8.5 standard deviations, and the decision here\n// asks for twice that distance (4·reach²) after moving the mean by twice its bound and the variance up by twice its bound.\nfn clip_state(m: f32, dm: f32, v: f32, dv: f32) -> u32 {\n let gap = 1.0 - m;\n let wide = 4.0 * params.reach2 * (v + 2.0 * dv);\n let below = gap - 2.0 * dm;\n let above = gap + 2.0 * dm;\n if (below > 0.0 && below * below > wide) { return 0u; }\n if (above < 0.0 && above * above > wide) { return 1u; }\n return 2u;\n}\n// Moments of min(Y, top) for Y ~ N(m, v): (mean, variance, slope P). The variance is v·(P − zφ + z²Q − δ²) with\n// δ = φ − zQ: algebraically E[min²] − E[min]² without the m² cancellation.\nfn upper_clip(m: f32, v: f32, top: f32) -> vec3<f32> {\n if (!(v > 0.0)) { return vec3<f32>(min(m, top), 0.0, select(0.0, 1.0, m < top)); }\n let s = sqrt(v);\n let z = (top - m) / s;\n if (z > CLIP_REACH) { return vec3<f32>(m, v, 1.0); }\n if (z < -CLIP_REACH) { return vec3<f32>(top, 0.0, 0.0); }\n let p = pq(z);\n let d = phi(z);\n let delta = d - z * p.y;\n let mean = m - s * delta;\n let ratio = p.x - z * d + z * z * p.y - delta * delta;\n return vec3<f32>(mean, v * max(0.0, ratio), p.x);\n}\n// Moments of clip(Y, 0, 1) for Y with mean m, variance v and standardized skewness γ (|γ| ≤ 1): (mean, variance, inside).\n// With Z standard normal, W = m + s·g(Z), g = clip(Z, a, b): E[g] = aΦa + φa − φb + bQb, E[g²] = a²Φa + (Φb − Φa) −\n// (bφb − aφa) + b²Qb; the mean adds the reference's Edgeworth term (s·γ/6)·(aφa − bφb).\nfn unit_clip(m: f32, v: f32, skewness: f32) -> vec3<f32> {\n if (!(v > 0.0)) { return vec3<f32>(clamp(m, 0.0, 1.0), 0.0, select(0.0, 1.0, m > 0.0 && m < 1.0)); }\n let s = sqrt(v);\n let a = -m / s;\n let b = (1.0 - m) / s;\n if (a < -CLIP_REACH && b > CLIP_REACH) { return vec3<f32>(m, v, 1.0); }\n var pa = 0.0; var da = 0.0;\n if (!(a < -CLIP_REACH)) { pa = pq(a).x; da = phi(a); }\n var pb = 1.0; var qb = 0.0; var db = 0.0;\n if (!(b > CLIP_REACH)) { let p = pq(b); pb = p.x; qb = p.y; db = phi(b); }\n let inside = pb - pa;\n let gamma = clamp(skewness, -1.0, 1.0);\n let aa = a * da;\n let bb = b * db;\n let eg = a * pa + (da - db) + b * qb;\n let eg2 = a * a * pa + inside - (bb - aa) + b * b * qb;\n let normal_mean = m + s * eg;\n var mean = normal_mean;\n var skew_shift = 0.0;\n if (gamma != 0.0) { skew_shift = s * gamma / 6.0 * (aa - bb); mean = normal_mean + skew_shift; }\n // The reference forms E[Y²] − (E[Y] + shift)², so the shift also enters its variance: −shift·(2·E[Y] + shift).\n return vec3<f32>(mean, max(0.0, v * (eg2 - eg * eg) - skew_shift * (2.0 * normal_mean + skew_shift)), inside);\n}\n// Positive Reinhard per channel then the clip to [0, 1]: h(x) = x/(1 + x) for x > 0, else 0. Composite 16-point\n// Gauss–Legendre over [max(0, m − 8.5s), m + 8.5s] in 4 panels, as the reference; the variance is formed about h(m).\nfn reinhard_moments(m: f32, v: f32) -> vec3<f32> {\n if (!(v > 0.0)) {\n if (m > 0.0) { return vec3<f32>(m / (1.0 + m), 0.0, 1.0 / ((1.0 + m) * (1.0 + m))); }\n return vec3<f32>(0.0, 0.0, 0.0);\n }\n let s = sqrt(v);\n // The reference's panels [max(0, m − 8.5s), m + 8.5s] in standardized units z = (x − m)/s, so the node's z is formed\n // without the cancellation x − m: zlo = max(−m/s, −8.5), weight = zhalf·w_k·φ(z_k) (= half·w_k·φ((x − m)/s)/s), x = m + s·z.\n let zlo = max(-m / s, -CLIP_REACH);\n if (!(CLIP_REACH > zlo)) { return vec3<f32>(0.0, 0.0, 0.0); }\n let hm = select(0.0, m / (1.0 + m), m > 0.0);\n var e1 = 0.0; var e2 = 0.0; var ed = 0.0;\n let zwidth = (CLIP_REACH - zlo) / 4.0;\n for (var p = 0u; p < 4u; p = p + 1u) {\n let zc = zlo + (f32(p) + 0.5) * zwidth;\n let zhalf = zwidth / 2.0;\n for (var k = 0u; k < 16u; k = k + 1u) {\n let z = zc + zhalf * aux[${DISPLAY_VIEW_AUX.gaussLegendre}u + k];\n let x = m + s * z;\n let weight = zhalf * aux[${DISPLAY_VIEW_AUX.gaussLegendre + 16}u + k] * phi(z);\n let h = x / (1.0 + x);\n e1 = e1 + weight * h;\n e2 = e2 + weight * (h - hm) * (h - hm);\n ed = ed + weight / ((1.0 + x) * (1.0 + x));\n }\n }\n let shifted = e1 - hm;\n return vec3<f32>(e1, max(0.0, e2 - shifted * shifted), ed);\n}\nfn reflect_x(x: i32) -> i32 { if (x < 0) { return -x; } if (x >= i32(params.native_w)) { return 2 * i32(params.native_w) - 2 - x; } return x; }\nfn reflect_y(y: i32) -> i32 { if (y < 0) { return -y; } if (y >= i32(params.native_h)) { return 2 * i32(params.native_h) - 2 - y; } return y; }\nfn channel_of(x: i32, y: i32) -> u32 {\n if ((y & 1) == 0) { return select(1u, 0u, (x & 1) == 0); }\n return select(2u, 1u, (x & 1) == 0);\n}\nfn material_signal(m: u32, c: u32) -> f32 {\n let n = params.nodes;\n var s = 0.0;\n var b = 0.0;\n for (var k = 0u; k < n; k = k + 1u) {\n b = b + spectral_table[c * n + k] * spectral_table[(3u + m) * n + k];\n if ((k & 15u) == 15u) { s = s + b; b = 0.0; }\n }\n return s + b;\n}\n// The expected photo electrons of native site (x, y): Σ_o w_o·scene_value(p_o, c) in offset order (directSite); with a material\n// module scene_value is S_c(m_o), integrated from the material's spectrum (material_signal).\nfn site_electrons(x: i32, y: i32, c: u32) -> f32 {\n var sum = 0.0;\n let fx = f32(x);\n let fy = f32(y);\n for (var o = 0u; o < params.offsets; o = o + 1u) {\n let base = ${DISPLAY_VIEW_AUX.offsets}u + 4u * o;\n let u = (fx + aux[base]) * params.scale_u;\n let v = (fy + aux[base + 1u]) * params.scale_v;\n sum = sum + aux[base + 2u] * scene_value(vec2<f32>(u, v), c);\n }\n return sum;\n}\n@compute @workgroup_size(${DISPLAY_VIEW_WORKGROUP_SIZE})\nfn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) groups: vec3<u32>) {\n let i = gid.x + gid.y * groups.x * ${DISPLAY_VIEW_WORKGROUP_SIZE}u;\n if (i >= params.count) { return; }\n material_uncertain = false;\n let rx = i % params.region_w;\n let ry = params.row0 + i / params.region_w;\n let col = rx * STRIDE;\n let row = (params.columns + ry) * STRIDE;\n let col_first = bitcast<i32>(geometry[col]);\n let nx = bitcast<u32>(geometry[col + 1u]);\n let row_first = bitcast<i32>(geometry[row]);\n let ny = bitcast<u32>(geometry[row + 1u]);\n let margin = i32(params.margin);\n // 2. and 3.: the sites of the footprint plus one site of reach, once each.\n let x0 = col_first + margin - 1;\n let y0 = row_first + margin - 1;\n let window_w = nx + 2u;\n for (var sj = 0u; sj < ny + 2u; sj = sj + 1u) {\n let sy = reflect_y(y0 + i32(sj));\n for (var si = 0u; si < window_w; si = si + 1u) {\n let sx = reflect_x(x0 + i32(si));\n let c = channel_of(sx, sy);\n let e = site_electrons(sx, sy, c) + dark_of(c);\n let kc = k_of(c);\n let mean = kc * e;\n let variance = kc * kc * e + c0_of(c);\n let gap = 1.0 - mean;\n let slot = sj * window_w + si;\n site_third[slot] = kc * kc * kc * e;\n site_clip[slot] = clip_state(mean, SITE_RELATIVE_U * E * mean, variance, SITE_RELATIVE_U * E * variance);\n if (gap > 0.0 && gap * gap > params.reach2 * variance) {\n site_mean[slot] = mean; site_var[slot] = variance; site_bound[slot] = 0.0;\n } else {\n let clipped = upper_clip(mean, variance, 1.0);\n site_mean[slot] = clipped.x; site_var[slot] = clipped.y; site_bound[slot] = sqrt(variance);\n }\n }\n }\n // B_c of the footprint from the host's axis sums (each over its scale squared): red, green, blue.\n let xb_even = geometry[col + 8u]; let xb_odd = geometry[col + 9u];\n let xpp_even = geometry[col + 10u]; let xpp_odd = geometry[col + 11u];\n let xqq_even = geometry[col + 12u]; let xqq_odd = geometry[col + 13u];\n let xpq_even = geometry[col + 14u]; let xpq_odd = geometry[col + 15u];\n let yb_even = geometry[row + 8u]; let yb_odd = geometry[row + 9u];\n let ypp_even = geometry[row + 10u]; let ypp_odd = geometry[row + 11u];\n let yqq_even = geometry[row + 12u]; let yqq_odd = geometry[row + 13u];\n let ypq_even = geometry[row + 14u]; let ypq_odd = geometry[row + 15u];\n let b0 = xb_even * yb_even;\n let b1 = (xpp_odd * ypp_even + xqq_odd * ypp_even + xpp_odd * yqq_even + 2.0 * xpq_odd * ypp_even + 2.0 * xpp_odd * ypq_even + 2.0 * xpq_odd * ypq_even) +\n (xpp_even * ypp_odd + xqq_even * ypp_odd + xpp_even * yqq_odd + 2.0 * xpq_even * ypp_odd + 2.0 * xpp_even * ypq_odd + 2.0 * xpq_even * ypq_odd);\n let b2 = xb_odd * yb_odd;\n let reinhard = params.tone == 1u;\n var s0 = 0.0; var s1 = 0.0; var s2 = 0.0;\n var c00 = 0.0; var c01 = 0.0; var c02 = 0.0; var c11 = 0.0; var c12 = 0.0; var c22 = 0.0;\n var r0 = 0.0; var r1 = 0.0; var r2 = 0.0;\n var bound_mean = 0.0; var bound_var = 0.0;\n // #533: the saturated real pixels (bit j·nx + i) and whether any real pixel is undecided.\n var mask0 = 0u; var mask1 = 0u; var undecided = false;\n // 4. and 5.: every real pixel of the footprint with its overlap weight.\n for (var j = 0u; j < ny; j = j + 1u) {\n let ay = geometry[row + 2u + j];\n for (var ii = 0u; ii < nx; ii = ii + 1u) {\n let aj = geometry[col + 2u + ii] * ay;\n let x = col_first + i32(ii) + margin;\n let y = row_first + i32(j) + margin;\n let phase = u32(y & 1) * 2u + u32(x & 1);\n var cm: array<f32, 3>; var cvv: array<f32, 3>; var cth: array<f32, 3>; var csv: array<f32, 3>; var cb: array<f32, 3>;\n var clipped = false; var near_white = false;\n for (var c = 0u; c < 3u; c = c + 1u) {\n var mean = 0.0; var variance = 0.0; var third = 0.0; var bnd = 0.0;\n let taps = ${DISPLAY_VIEW_AUX.taps}u + (phase * 3u + c) * 16u;\n for (var t = 0u; t < 4u; t = t + 1u) {\n let w = aux[taps + 4u * t + 2u];\n let slot = u32((i32(j) + 1 + i32(aux[taps + 4u * t + 1u])) * i32(window_w) + i32(ii) + 1 + i32(aux[taps + 4u * t]));\n mean = mean + w * site_mean[slot];\n variance = variance + w * w * site_var[slot];\n third = third + w * w * w * site_third[slot];\n bnd = max(bnd, select(0.0, site_bound[slot], w != 0.0));\n if (w != 0.0) { if (site_clip[slot] == 1u) { clipped = true; } else if (site_clip[slot] == 2u) { near_white = true; } }\n }\n cm[c] = mean; cvv[c] = variance; cth[c] = third; cb[c] = bnd;\n csv[c] = variance * aux[${DISPLAY_VIEW_AUX.inverseW2}u + phase * 3u + c];\n }\n if (clipped) {\n let bit = j * nx + ii;\n if (bit < 32u) { mask0 = mask0 | (1u << bit); } else { mask1 = mask1 | (1u << (bit - 32u)); }\n } else if (near_white) { undecided = true; }\n // White balance and the highlight clip at the smallest gain: bm, bv, bs (slope), with the clip's bound terms.\n var bm: array<f32, 3>; var bv: array<f32, 3>; var bs: array<f32, 3>; var bbm: array<f32, 3>; var bbv: array<f32, 3>;\n for (var c = 0u; c < 3u; c = c + 1u) {\n let gc = g_of(c);\n let um = gc * cm[c];\n let uv = gc * gc * cvv[c];\n let gap = params.clip_level - um;\n bbm[c] = gc * CLIP_MEAN_U * cb[c];\n bbv[c] = gc * gc * CLIP_VARIANCE_U * cb[c] * cb[c];\n if (gap > 0.0 && gap * gap > params.reach2 * uv) { bm[c] = um; bv[c] = uv; bs[c] = gc; }\n else {\n let clipped = upper_clip(um, uv, params.clip_level);\n bm[c] = clipped.x; bv[c] = clipped.y; bs[c] = gc * clipped.z;\n bbm[c] = bbm[c] + CLIP_MEAN_U * sqrt(uv);\n bbv[c] = bbv[c] + CLIP_VARIANCE_U * uv;\n }\n }\n // Colour matrix, then the rendering of each component (tone curve, clip to [0, 1]).\n var hm: array<f32, 3>; var hv: array<f32, 3>; var hs: array<f32, 3>; var hbm: array<f32, 3>; var hbv: array<f32, 3>;\n for (var comp = 0u; comp < 3u; comp = comp + 1u) {\n let r0m = m_of(comp, 0u); let r1m = m_of(comp, 1u); let r2m = m_of(comp, 2u);\n let mean = r0m * bm[0] + r1m * bm[1] + r2m * bm[2];\n let variance = r0m * r0m * bv[0] + r1m * r1m * bv[1] + r2m * r2m * bv[2];\n var bm_c = abs(r0m) * bbm[0] + abs(r1m) * bbm[1] + abs(r2m) * bbm[2];\n var bv_c = r0m * r0m * bbv[0] + r1m * r1m * bbv[1] + r2m * r2m * bbv[2];\n if (!reinhard && mean > 0.0 && mean < 1.0 && mean * mean > params.reach2 * variance && (1.0 - mean) * (1.0 - mean) > params.reach2 * variance) {\n hm[comp] = mean; hv[comp] = variance; hs[comp] = 1.0;\n } else if (reinhard) {\n let moments = reinhard_moments(mean, variance);\n hm[comp] = moments.x; hv[comp] = moments.y; hs[comp] = moments.z;\n bm_c = bm_c + 2.0 * CLIP_MEAN_U * sqrt(variance);\n bv_c = bv_c + 2.0 * CLIP_VARIANCE_U * variance;\n } else {\n // κ₃ of the component: Σ_c (M_comp,c·Γ_c)³·Σ_t w_t³·κ₃(site) (the sites of one channel share the coefficient).\n let k0 = r0m * bs[0]; let k1 = r1m * bs[1]; let k2 = r2m * bs[2];\n let third = k0 * k0 * k0 * cth[0] + k1 * k1 * k1 * cth[1] + k2 * k2 * k2 * cth[2];\n let skew = select(0.0, third / (variance * sqrt(variance)), variance > 0.0);\n let moments = unit_clip(mean, variance, skew);\n hm[comp] = moments.x; hv[comp] = moments.y; hs[comp] = moments.z;\n bm_c = bm_c + 2.0 * CLIP_MEAN_U * sqrt(variance);\n bv_c = bv_c + 2.0 * CLIP_VARIANCE_U * variance;\n }\n hbm[comp] = bm_c; hbv[comp] = bv_c;\n }\n s0 = s0 + aj * hm[0]; s1 = s1 + aj * hm[1]; s2 = s2 + aj * hm[2];\n // Linear (Stein) part with B_c·σ_c², and the pixel's own linear variance for the residual.\n var l0 = 0.0; var l1 = 0.0; var l2 = 0.0;\n var lb0 = 0.0; var lb1 = 0.0; var lb2 = 0.0;\n for (var c = 0u; c < 3u; c = c + 1u) {\n let a0 = hs[0] * m_of(0u, c) * bs[c];\n let a1 = hs[1] * m_of(1u, c) * bs[c];\n let a2 = hs[2] * m_of(2u, c) * bs[c];\n var bc = b0; if (c == 1u) { bc = b1; } if (c == 2u) { bc = b2; }\n let wgt = aj * bc * csv[c];\n c00 = c00 + wgt * a0 * a0; c01 = c01 + wgt * a0 * a1; c02 = c02 + wgt * a0 * a2;\n c11 = c11 + wgt * a1 * a1; c12 = c12 + wgt * a1 * a2; c22 = c22 + wgt * a2 * a2;\n l0 = l0 + a0 * a0 * cvv[c]; l1 = l1 + a1 * a1 * cvv[c]; l2 = l2 + a2 * a2 * cvv[c];\n // The clip bound of each channel's variance enters the covariance through a_j·B_c·(Δσ_c²/Σw²)·a_i·a_j and the\n // residual's linear prediction through a²·Δσ_c².\n lb0 = lb0 + (a0 * a0) * bbv[c]; lb1 = lb1 + (a1 * a1) * bbv[c]; lb2 = lb2 + (a2 * a2) * bbv[c];\n bound_var = bound_var + aj * bc * (bbv[c] * aux[${DISPLAY_VIEW_AUX.inverseW2}u + phase * 3u + c]) * max(a0 * a0, max(a1 * a1, a2 * a2));\n }\n r0 = r0 + aj * aj * max(0.0, hv[0] - l0);\n r1 = r1 + aj * aj * max(0.0, hv[1] - l1);\n r2 = r2 + aj * aj * max(0.0, hv[2] - l2);\n bound_mean = bound_mean + aj * max(hbm[0], max(hbm[1], hbm[2]));\n bound_var = bound_var + aj * aj * (max(hbv[0], max(hbv[1], hbv[2])) + max(lb0, max(lb1, lb2)));\n }\n }\n let o = i * ${DISPLAY_VIEW_OUTPUT_FLOATS}u;\n out[o] = s0; out[o + 1u] = s1; out[o + 2u] = s2;\n out[o + 3u] = c00 + r0; out[o + 4u] = c11 + r1; out[o + 5u] = c22 + r2;\n out[o + 6u] = c01; out[o + 7u] = c02; out[o + 8u] = c12;\n out[o + 9u] = bound_mean * E; out[o + 10u] = bound_var * E;\n flags[3u * i] = select(0u, 1u, material_uncertain) | select(0u, 2u, undecided);\n flags[3u * i + 1u] = mask0;\n flags[3u * i + 2u] = mask1;\n}\n`;\n\n/**\n * The channel signal of the material a material module's `material_at` gives (the kernel's `scene_value`), integrated from its\n * spectrum when it changes (2.21.0: signals are integrated from the material spectrum per site).\n */\nexport const DISPLAY_VIEW_MATERIAL_SCENE_VALUE_WGSL = /* wgsl */ `\nvar<private> scene_m: u32 = 0xffffffffu;\nvar<private> scene_c: u32 = 0u;\nvar<private> scene_s: f32 = 0.0;\nfn scene_value(p: vec2<f32>, c: u32) -> f32 {\n let m = material_at(p);\n if (m != scene_m || c != scene_c) { scene_s = material_signal(m, c); scene_m = m; scene_c = c; }\n return scene_s;\n}\n`;\n/** The full shader: the kernel plus a material module (see `DISPLAY_VIEW_SPEED_KERNEL_WGSL`), and the table adapter unless the module defines `scene_value`. */\nexport function assembleDisplayViewSpeedWgsl(materialModuleWgsl: string): string {\n const adapter = /\\bfn scene_value\\(/u.test(materialModuleWgsl) ? \"\" : DISPLAY_VIEW_MATERIAL_SCENE_VALUE_WGSL;\n return DISPLAY_VIEW_SPEED_KERNEL_WGSL + \"\\n\" + materialModuleWgsl + \"\\n\" + adapter;\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A sum of non-negative float32 values in integer arithmetic (2.21.0), for the display view's kernels, which integrate a site's
|
|
3
|
+
* signal from the material spectrum per site: Σ_n A_c(λ_n)·L_m(λ_n) (Speed) and the per-node partials Σ_n P_n plus the dark
|
|
4
|
+
* electrons (Quality). Integer operations are exact on every device (W3C WGSL § 8.6), so the sum depends on no rounding mode,
|
|
5
|
+
* fusion or reassociation, and only the final conversion rounds:
|
|
6
|
+
*
|
|
7
|
+
* - **Accumulator.** 64 bits in two words. The caller first takes `anchor`, the largest biased exponent among the terms
|
|
8
|
+
* (`exact_exponent`); each term's 24-bit significand m is added with its least significant bit at bit 32 − (anchor − e), so the
|
|
9
|
+
* largest term occupies bits 32 … 55 and up to 255 terms cannot carry past bit 63.
|
|
10
|
+
* - **Truncation.** Bits that fall below bit 0 are dropped: each term loses less than one unit of 2^(anchor − 182), so N ≤ 255
|
|
11
|
+
* terms lose less than 2⁻⁴⁷ of the largest term, relative.
|
|
12
|
+
* - **Result.** The accumulator's top 32 bits (truncated: below 2⁻³¹ relative; with a zero high word, the low word, as WGSL takes
|
|
13
|
+
* shift amounts modulo 32) converted to float32, which rounds to one of the
|
|
14
|
+
* two neighbours (W3C WGSL, "Floating Point Conversion"), then scaled by a power of two with `ldexp` (exact): at most one
|
|
15
|
+
* rounding, E relative, for any number of terms. A result below the float32 normal range may be flushed to 0 (an absolute error
|
|
16
|
+
* below 2⁻¹²⁶, which the hosts' absolute terms cover); the hosts keep every sum far below the float32 overflow threshold.
|
|
17
|
+
*
|
|
18
|
+
* Mirrored line by line in JavaScript by test/helpers/exact-sum-emulation.ts.
|
|
19
|
+
*/
|
|
20
|
+
export declare const EXACT_SUM_WGSL = "\nstruct ExactSum { lo: u32, hi: u32, anchor: u32 }\nfn exact_exponent(v: f32) -> u32 { return max((bitcast<u32>(v) >> 23u) & 0xffu, 1u); }\nfn exact_add(a: ptr<function, ExactSum>, v: f32) {\n let bits = bitcast<u32>(v);\n let be = (bits >> 23u) & 0xffu;\n let m = (bits & 0x7fffffu) | select(0u, 0x800000u, be != 0u);\n let s = (*a).anchor - max(be, 1u);\n var lo = 0u;\n var hi = 0u;\n if (s == 0u) { hi = m; } else if (s < 32u) { hi = m >> s; lo = m << (32u - s); } else if (s < 56u) { lo = m >> (s - 32u); }\n let t = (*a).lo + lo;\n (*a).hi = (*a).hi + hi + select(0u, 1u, t < lo);\n (*a).lo = t;\n}\nfn exact_round(a: ptr<function, ExactSum>) -> f32 {\n let z = countLeadingZeros((*a).hi);\n let t = ((*a).hi << z) | select(0u, (*a).lo >> (32u - z), z != 0u);\n return ldexp(f32(t), i32((*a).anchor) - 150 - i32(z));\n}\n";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* A sum of non-negative float32 values in integer arithmetic (2.21.0), for the display view's kernels, which integrate a site's
|
|
4
|
+
* signal from the material spectrum per site: Σ_n A_c(λ_n)·L_m(λ_n) (Speed) and the per-node partials Σ_n P_n plus the dark
|
|
5
|
+
* electrons (Quality). Integer operations are exact on every device (W3C WGSL § 8.6), so the sum depends on no rounding mode,
|
|
6
|
+
* fusion or reassociation, and only the final conversion rounds:
|
|
7
|
+
*
|
|
8
|
+
* - **Accumulator.** 64 bits in two words. The caller first takes `anchor`, the largest biased exponent among the terms
|
|
9
|
+
* (`exact_exponent`); each term's 24-bit significand m is added with its least significant bit at bit 32 − (anchor − e), so the
|
|
10
|
+
* largest term occupies bits 32 … 55 and up to 255 terms cannot carry past bit 63.
|
|
11
|
+
* - **Truncation.** Bits that fall below bit 0 are dropped: each term loses less than one unit of 2^(anchor − 182), so N ≤ 255
|
|
12
|
+
* terms lose less than 2⁻⁴⁷ of the largest term, relative.
|
|
13
|
+
* - **Result.** The accumulator's top 32 bits (truncated: below 2⁻³¹ relative; with a zero high word, the low word, as WGSL takes
|
|
14
|
+
* shift amounts modulo 32) converted to float32, which rounds to one of the
|
|
15
|
+
* two neighbours (W3C WGSL, "Floating Point Conversion"), then scaled by a power of two with `ldexp` (exact): at most one
|
|
16
|
+
* rounding, E relative, for any number of terms. A result below the float32 normal range may be flushed to 0 (an absolute error
|
|
17
|
+
* below 2⁻¹²⁶, which the hosts' absolute terms cover); the hosts keep every sum far below the float32 overflow threshold.
|
|
18
|
+
*
|
|
19
|
+
* Mirrored line by line in JavaScript by test/helpers/exact-sum-emulation.ts.
|
|
20
|
+
*/
|
|
21
|
+
export const EXACT_SUM_WGSL = /* wgsl */ `
|
|
22
|
+
struct ExactSum { lo: u32, hi: u32, anchor: u32 }
|
|
23
|
+
fn exact_exponent(v: f32) -> u32 { return max((bitcast<u32>(v) >> 23u) & 0xffu, 1u); }
|
|
24
|
+
fn exact_add(a: ptr<function, ExactSum>, v: f32) {
|
|
25
|
+
let bits = bitcast<u32>(v);
|
|
26
|
+
let be = (bits >> 23u) & 0xffu;
|
|
27
|
+
let m = (bits & 0x7fffffu) | select(0u, 0x800000u, be != 0u);
|
|
28
|
+
let s = (*a).anchor - max(be, 1u);
|
|
29
|
+
var lo = 0u;
|
|
30
|
+
var hi = 0u;
|
|
31
|
+
if (s == 0u) { hi = m; } else if (s < 32u) { hi = m >> s; lo = m << (32u - s); } else if (s < 56u) { lo = m >> (s - 32u); }
|
|
32
|
+
let t = (*a).lo + lo;
|
|
33
|
+
(*a).hi = (*a).hi + hi + select(0u, 1u, t < lo);
|
|
34
|
+
(*a).lo = t;
|
|
35
|
+
}
|
|
36
|
+
fn exact_round(a: ptr<function, ExactSum>) -> f32 {
|
|
37
|
+
let z = countLeadingZeros((*a).hi);
|
|
38
|
+
let t = ((*a).hi << z) | select(0u, (*a).lo >> (32u - z), z != 0u);
|
|
39
|
+
return ldexp(f32(t), i32((*a).anchor) - 150 - i32(z));
|
|
40
|
+
}
|
|
41
|
+
`;
|
|
42
|
+
//# sourceMappingURL=wgsl-exact-sum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wgsl-exact-sum.js","sourceRoot":"","sources":["../../src/gpu/wgsl-exact-sum.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;CAoBxC,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * A sum of non-negative float32 values in integer arithmetic (2.21.0), for the display view's kernels, which integrate a site's\n * signal from the material spectrum per site: Σ_n A_c(λ_n)·L_m(λ_n) (Speed) and the per-node partials Σ_n P_n plus the dark\n * electrons (Quality). Integer operations are exact on every device (W3C WGSL § 8.6), so the sum depends on no rounding mode,\n * fusion or reassociation, and only the final conversion rounds:\n *\n * - **Accumulator.** 64 bits in two words. The caller first takes `anchor`, the largest biased exponent among the terms\n * (`exact_exponent`); each term's 24-bit significand m is added with its least significant bit at bit 32 − (anchor − e), so the\n * largest term occupies bits 32 … 55 and up to 255 terms cannot carry past bit 63.\n * - **Truncation.** Bits that fall below bit 0 are dropped: each term loses less than one unit of 2^(anchor − 182), so N ≤ 255\n * terms lose less than 2⁻⁴⁷ of the largest term, relative.\n * - **Result.** The accumulator's top 32 bits (truncated: below 2⁻³¹ relative; with a zero high word, the low word, as WGSL takes\n * shift amounts modulo 32) converted to float32, which rounds to one of the\n * two neighbours (W3C WGSL, \"Floating Point Conversion\"), then scaled by a power of two with `ldexp` (exact): at most one\n * rounding, E relative, for any number of terms. A result below the float32 normal range may be flushed to 0 (an absolute error\n * below 2⁻¹²⁶, which the hosts' absolute terms cover); the hosts keep every sum far below the float32 overflow threshold.\n *\n * Mirrored line by line in JavaScript by test/helpers/exact-sum-emulation.ts.\n */\nexport const EXACT_SUM_WGSL = /* wgsl */ `\nstruct ExactSum { lo: u32, hi: u32, anchor: u32 }\nfn exact_exponent(v: f32) -> u32 { return max((bitcast<u32>(v) >> 23u) & 0xffu, 1u); }\nfn exact_add(a: ptr<function, ExactSum>, v: f32) {\n let bits = bitcast<u32>(v);\n let be = (bits >> 23u) & 0xffu;\n let m = (bits & 0x7fffffu) | select(0u, 0x800000u, be != 0u);\n let s = (*a).anchor - max(be, 1u);\n var lo = 0u;\n var hi = 0u;\n if (s == 0u) { hi = m; } else if (s < 32u) { hi = m >> s; lo = m << (32u - s); } else if (s < 56u) { lo = m >> (s - 32u); }\n let t = (*a).lo + lo;\n (*a).hi = (*a).hi + hi + select(0u, 1u, t < lo);\n (*a).lo = t;\n}\nfn exact_round(a: ptr<function, ExactSum>) -> f32 {\n let z = countLeadingZeros((*a).hi);\n let t = ((*a).hi << z) | select(0u, (*a).lo >> (32u - z), z != 0u);\n return ldexp(f32(t), i32((*a).anchor) - 150 - i32(z));\n}\n`;\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -83,9 +83,11 @@ export { calculateSensorReadoutTiming, type CalculateSensorReadoutTimingInput, t
|
|
|
83
83
|
export { calculateCaptureExposureWindows, type CalculateCaptureExposureWindowsInput, type CaptureExposureBoundaryActuator, type CaptureExposureWindowSample, type CaptureExposureWindows, type ExposureBoundarySchedule, type ResolvedCaptureExposureBoundary, type SimultaneousExposureBoundarySchedule, type SourcedCaptureBoundaryDirection, type SourcedCaptureTimingSeconds, type UniformLinearExposureBoundarySchedule } from "./sensor/exposure-window.js";
|
|
84
84
|
export { assessReadoutExposureTimingLinkage, resolveElectronicRollingShutterExposureSchedule, createRollingShutterCaptureExposureSchedule, ELECTRONIC_ROLLING_SHUTTER_MODEL, type ResolveElectronicRollingShutterExposureScheduleInput, type ElectronicRollingShutterExposureSchedule, type AssessReadoutExposureTimingLinkageInput, type ReadoutExposureBoundaryId, type ReadoutExposureBoundarySpatialLink, type ReadoutExposureBoundarySpatialLinkAssessment, type ReadoutExposureSpatialPhaseOrientation, type ReadoutExposureTimingLinkageAssessment, type ReadoutExposureTimingLinkageDeclaration } from "./sensor/readout-exposure-linkage.js";
|
|
85
85
|
export { calculateCenteredCrop, type CalculateCenteredCropInput, type CenteredCrop } from "./output/crop.js";
|
|
86
|
+
export { calculateCropToMatchFocalLength, type CalculateCropToMatchFocalLengthInput, type CropToMatchFocalLength } from "./output/crop-to-match-focal-length.js";
|
|
86
87
|
export { calculateSubjectFramingCrop, type CalculateSubjectFramingCropInput, type SubjectFramingCrop } from "./output/subject-framing-crop.js";
|
|
87
88
|
export { calculateActiveCaptureFieldOfView, calculateOutputFieldOfView, mapImagePlanePointToOrientedPhysicalUv, mapOrientedPhysicalUvToImagePlanePoint, resolveCaptureGeometry, transformNativeRasterPointToOriented, transformNativeRasterRectToOriented, transformNativeRasterVectorToOriented, transformOrientedRasterPointToNative, transformOrientedRasterRectToNative, transformOrientedRasterVectorToNative, type ActiveCaptureFieldOfView, type CalculateActiveCaptureFieldOfViewInput, type CalculateOutputFieldOfViewInput, type CaptureOrientation, type ImagePlaneMetricPointMm, type MapImagePlanePointToOrientedPhysicalUvInput, type MapOrientedPhysicalUvToImagePlaneInput, type NormalizedRasterUv, type OutputFieldOfView, type PhysicalBoundsFromOpticalAxisMm, type RasterPoint, type RasterRect, type RasterVector, type ResolveCaptureGeometryInput, type ResolvedCaptureGeometry, type TransformRasterPointInput, type TransformRasterRectInput, type TransformRasterVectorInput } from "./output/capture-geometry.js";
|
|
88
89
|
export { calculateIdealApertureGeometry, type ApertureVertex, type CalculateIdealApertureInput, type IdealApertureGeometry } from "./optics/aperture.js";
|
|
90
|
+
export { calculateApertureDiameter, type ApertureDiameter, type CalculateApertureDiameterInput } from "./optics/aperture-diameter.js";
|
|
89
91
|
export { calculateAiryDisk, type AiryDisk, type CalculateAiryDiskInput } from "./optics/diffraction.js";
|
|
90
92
|
export { calculateIdealPolygonDiffractionPsf, calculatePolygonPupilFraunhoferPsf, type CalculateIdealPolygonDiffractionInput, type CalculatePolygonPupilFraunhoferPsfInput, type IdealPolygonDiffraction, type PolygonPupilFraunhoferPsf } from "./optics/polygon-diffraction.js";
|
|
91
93
|
export { ZERNIKE_MAXIMUM_NOLL_INDEX, ZERNIKE_PUPIL_MAXIMUM_SAMPLES_ACROSS, calculateDefocusWavefront, createWavefrontPupilGrid, estimateMarechalStrehlRatio, evaluateZernikePolynomial, resolveZernikeNollOrder, type CalculateDefocusWavefrontInput, type CreateWavefrontPupilGridInput, type DefocusWavefront, type EstimateMarechalStrehlRatioInput, type SeidelFieldPosition, type SeidelWavefrontCoefficients, type WavefrontPupilGrid, type ZernikeCoefficient, type ZernikeOrder } from "./optics/zernike-wavefront.js";
|
|
@@ -160,7 +162,9 @@ export { calculateEnvironmentSensorPhotoSignal, type CalculateEnvironmentSensorP
|
|
|
160
162
|
export { simulateEnvironmentSensorRawFrame, type SimulateEnvironmentSensorRawFrameInput, type EnvironmentSensorRawFrame } from "./capture/environment-raw-producer.js";
|
|
161
163
|
export { calculateProcessedSensorRaw, parseProcessedSensorRawInput, type ProcessedSensorRawInput, type ProcessedSensorRawResult } from "./capture/photographic-export.js";
|
|
162
164
|
export { calculatePrintPlan, calculatePrintSizeLimit, parsePrintPlanInput } from "./output/print-plan.js";
|
|
163
|
-
export type { PrintLength, PrintedImageSize, PrintSamplingCriterion, PrintNativeSource, PrintProviderConstraints, PrintPlanInput, PrintRasterSampling, PrintPlan, PrintSizeLimitInput, PrintSizeLimit } from "./output/print-plan.js";
|
|
165
|
+
export type { PrintLength, PrintedImageSize, PrintSamplingCriterion, PrintNativeSource, PrintProviderConstraints, PrintPlanInput, PrintRasterSampling, PrintPlan, PrintSizeLimitInput, PrintSizeLimit, PrintFit, PrintContainLayout } from "./output/print-plan.js";
|
|
166
|
+
export { calculatePrintSizeLimitWithBlurAndNoise } from "./output/print-size-blur-noise.js";
|
|
167
|
+
export type { PrintBlurInput, PrintNoiseInput, PrintSharpCleanCriterion, PrintSizeLimitWithBlurAndNoiseInput, PrintImageMm, PrintSizeLimitWithBlurAndNoise } from "./output/print-size-blur-noise.js";
|
|
164
168
|
export { PRINT_REGION_DETAIL_MODEL_VERSION, MAX_PRINT_DETAIL_REGION_SAMPLES, calculatePrintRegionDetail, parsePrintRegionDetailInput } from "./output/print-detail.js";
|
|
165
169
|
export type { PrintDetailSource, PrintDetailRegion, PrintSinusoidalTarget, PrintRegionDetailInput, PrintSinusoidalMeasurement, PrintRegionDetailAssessment } from "./output/print-detail.js";
|
|
166
170
|
export { PRINT_REGION_STATISTICS_MODEL_VERSION, MAX_PRINT_REGION_STATISTICS_SAMPLES, calculatePrintRegionDifference, calculatePrintRegionNoise, parsePrintRegionDifferenceInput, parsePrintRegionNoiseInput } from "./output/print-region-statistics.js";
|
|
@@ -207,6 +211,11 @@ export { SYNTHETIC_FILM_GRAIN_STREAM_ID, createBilateralFilterTask, createNonLoc
|
|
|
207
211
|
export { calculateSensorApertureRays, type CalculateSensorApertureRaysInput, type IdealCircularPupil, type SensorApertureRay, type SensorApertureRays } from "./optics/sensor-aperture-rays.js";
|
|
208
212
|
export { SIMULATE_CAPTURE_FACADE_VERSION, SIMULATE_CAPTURE_DEFAULT_ILLUMINANCE_LUX, SIMULATE_CAPTURE_COST_OPTIONS, SIMULATE_CAPTURE_METERING_MODES, simulateCapture, type SimulateCaptureOptions, type SimulateCaptureResult, type SimulateCaptureAssumption, type SimulateCaptureProgress, type SimulateCaptureExposureMode, type SimulateCaptureMetering, type SimulateCaptureAutoIsoAfterMaximum, type SimulateCaptureAutoIsoReport, type SimulateCaptureAutomaticSlowestShutterOptions, type SimulateCaptureAutomaticSlowestShutterReport, type SimulateCaptureOutputFormat, type SimulateCaptureWhiteBalance, type SimulateCaptureColorEncoding, type SimulateCaptureDemosaic, type SimulateCaptureBorderHandling, type SimulateCaptureLensDistortion, type SimulateCaptureMotion, type SimulateCaptureSensorAntiAliasing, type SimulateCaptureCostOption, type SimulateCapturePixelAperture, SIMULATE_CAPTURE_BOX_APERTURE_DEFAULT_SAMPLES, SIMULATE_CAPTURE_FAST_OPTIONS, type SimulateCaptureFastOption, type SimulateCaptureFastReport, type SimulateCaptureDemosaicRecord, type SimulateCaptureLensCatalogueRecord, type SimulateCaptureSharpening, type SimulateCaptureDiffractionCorrection, type SimulateCaptureLensCorrections, type SimulateCaptureDetailDiagnostics, simulateIdealReference, type IdealReferenceResult, serializeSimulatedCaptureDngFromParts, type SimulateCaptureDngPart, type SimulateDisplayViewOptions, type DisplayViewResult, type DisplayViewHighlightDiagnostics, SIMULATE_DISPLAY_VIEW_DEFAULT_SAMPLES_PER_AXIS } from "./facade/simulate-capture.js";
|
|
209
213
|
export { simulateCaptureFromParts } from "./facade/develop-joined-parts.js";
|
|
214
|
+
export { EXPOSURE_BUILD_UP_MAXIMUM_FRACTIONS, EXPOSURE_BUILD_UP_STREAM_BASE, simulateExposureBuildUp, type SimulateExposureBuildUpFrame, type SimulateExposureBuildUpOptions, type SimulateExposureBuildUpResult } from "./facade/exposure-build-up.js";
|
|
215
|
+
export type { SimulateCaptureSensorCharacteristics, SimulateCaptureSensorReport, SimulateCaptureNoiseComponents } from "./sensor/sensor-characteristics.js";
|
|
216
|
+
export { SENSOR_PROFILES, SENSOR_PROFILE_IDS, resolveSensorProfile } from "./equipment/sensor-profiles.js";
|
|
217
|
+
export { SENSOR_PROFILE_ISO_ANCHOR, type SensorProfile, type SensorProfileValueKind } from "./equipment/sensor-profile-body.js";
|
|
218
|
+
export type { SimulateCaptureSubjectMotion } from "./motion/subject-motion.js";
|
|
210
219
|
export { simulateDisplayView, prepareDisplayView, type PreparedDisplayView, type PreparedDisplayViewRenderOptions, serializeDisplayViewCorrectionStates, bindDisplayViewCorrectionStates, type DisplayViewCorrectionStateKeys, type DisplayViewCorrectionStateSet } from "./facade/simulate-display-view.js";
|
|
211
220
|
export type { DisplayViewGpuMode, PrepareDisplayViewOptions, DisplayViewGpuFallbackReason, DisplayViewGpuConformance, DisplayViewExecution, DisplayViewFastReport } from "./facade/display-view-gpu.js";
|
|
212
221
|
export { type OutputTextMetadata, addJpegTextMetadata, addPngTextMetadata } from "./output/text-metadata.js";
|
|
@@ -214,11 +223,15 @@ export { GENERIC_THIRD_STOP_ISO_SETTINGS, GENERIC_THIRD_STOP_SHUTTER_SECONDS, GE
|
|
|
214
223
|
export { GENERIC_PRIME_EQUIVALENT_FOCAL_LENGTHS_MM, GENERIC_PRIME_THIRD_STOP_F_NUMBERS, GENERIC_PRIME_MINIMUM_FOCUS, resolveGenericPrimeLens, calculateGenericPrimeMinimumFocusDistanceM, type GenericPrimeLens, type GenericPrimeEquivalentFocalLengthMm } from "./equipment/generic-prime-lenses.js";
|
|
215
224
|
export { IDEAL_LENS_LIMITS } from "./equipment/ideal-lens.js";
|
|
216
225
|
export { GENERIC_LENS_CATALOGUE, GENERIC_LENS_IDS, GENERIC_LENS_SET_BASELINES, resolveGenericLens, simulateGenericLensFocusError, type GenericLensCatalogueEntry, type GenericLensSet, type GenericLensKind, type GenericLensCharacterValues, type GenericLensAdjustments, type GenericLensCharacter, type ResolvedGenericLens, type ResolveGenericLensInput, type SimulateGenericLensFocusErrorInput, type GenericLensFocusError } from "./equipment/generic-lens-catalogue.js";
|
|
217
|
-
export { createGenericLensCorrectionProfile, GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM, type CreateGenericLensCorrectionProfileInput } from "./output/generic-lens-corrections.js";
|
|
226
|
+
export { calculateChannelEffectiveDispersion, createGenericLensCorrectionProfile, GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM, type CalculateChannelEffectiveDispersionInput, type ChannelDispersion, type CreateGenericLensCorrectionProfileInput } from "./output/generic-lens-corrections.js";
|
|
227
|
+
export { calculateLateralColorFringe, type CalculateLateralColorFringeInput, type LateralColorFringe, type LateralColorDisplacement } from "./optics/generic-lens-lateral-color.js";
|
|
218
228
|
export { calculateChartFraming, calculateSubjectDistanceForFraming, type CalculateChartFramingInput, type CalculateSubjectDistanceForFramingInput, type ChartFraming, type SubjectFraming, type SubjectFramingFit } from "./facade/subject-framing.js";
|
|
219
229
|
export { CHART_SCENE_PRESETS, CHART_SCENE_DEFAULTS, CHART_SPECTRAL_RANGE_NANOMETERS, resolveChartScene, calculateStepWedgeReflectances, calculatePointGridCenters, type ChartScene, type ChartScenePresetId, type ChartReflectance, type ResolvedChartScene, type UniformChartScene, type SlantedEdgeChartScene, type SiemensStarChartScene, type StepWedgeChartScene, type GreyRampChartScene, type CheckerboardChartScene, type PointGridChartScene, type PatchChartScene, CHART_CONTINUOUS_LEVELS, calculateBarGroupTargets, calculateSlantedSquareEdges, type DeadLeavesChartScene, type BarGroupsChartScene, type HyperbolicWedgeChartScene, type ZonePlateChartScene, type SlantedSquaresChartScene, type LineGridChartScene, type FiducialChartScene, type CompositeChartScene, type CompositeChartElement, type ChartElementScene, type ChartRectangle, type ChartBarGroupTarget, type ChartSlantedSquare, type ColorPatchReflectance, type ColorPatchesChartScene } from "./facade/chart-scenes.js";
|
|
220
230
|
export { COLOR_PATCH_SET_ID, COLOR_PATCH_SET_VERSION, COLOR_PATCH_IDS, COLOR_PATCH_WAVELENGTH_RANGE_NANOMETERS, getColorPatchSet, evaluateColorPatchReflectance, type ColorPatch, type ColorPatchId, type ColorPatchGroup, type ColorPatchSet, type ColorPatchSpectralTerm, type EvaluateColorPatchReflectanceInput } from "./facade/color-patches.js";
|
|
221
|
-
export {
|
|
231
|
+
export { REPRESENTATIVE_LIGHT_SOURCE_SET_ID, REPRESENTATIVE_LIGHT_SOURCE_SET_VERSION, REPRESENTATIVE_LIGHT_SOURCE_IDS, REPRESENTATIVE_LIGHT_SOURCE_WAVELENGTH_RANGE_NANOMETERS, getRepresentativeLightSourceSet, createRepresentativeLightSourceSpectrum, createRepresentativeLightSourceIlluminant, type RepresentativeLightSource, type RepresentativeLightSourceBand, type RepresentativeLightSourceId, type RepresentativeLightSourceSet } from "./facade/representative-light-sources.js";
|
|
232
|
+
export { PHOTOPIC_MAXIMUM_LUMINOUS_EFFICACY_LM_PER_W, resolveCaptureIlluminant, createPlanarSceneRadianceProvider, CHART_SIZE_DEFAULT_SURROUND_REFLECTANCE, CALLER_MATERIAL_SCENE_MAX_MATERIALS, type ChartSizeOption, type CaptureIlluminant, type ResolvedCaptureIlluminant, type CallerReflectanceScene, type CallerRadianceScene, type CallerMaterialScene, type ScenePlanePoint, type SceneMaterialPoint, type PlanarSceneRadianceProvider, type ImagePlaneScene, type ImagePlaneImage } from "./facade/scene-radiance.js";
|
|
233
|
+
export { prepareImagePlaneScenes } from "./facade/image-plane-enable.js";
|
|
234
|
+
export type { MixedIllumination, MixedIlluminationBlend, MixedIlluminationPoint, MixedIlluminationPointSource, MixedIlluminationSource } from "./facade/mixed-illumination.js";
|
|
222
235
|
export { CHART_RADIANCE_BATCH_SCHEMA_VERSION, CHART_RADIANCE_BATCH_LIMITS, calculateChartRadianceBatchPlan, calculateChartRadianceBatch, mapEnvironmentDirectionsToChartPoints, type ChartRadianceBatchInput, type ChartRadianceBatchPlan } from "./facade/chart-radiance-batch.js";
|
|
223
236
|
export { resolveChartMaterialLayers, CHART_MASK_INDEX_GRAIN, CHART_MATERIAL_LAYER_LIMITS, type ChartMaterialLayerScene, type ChartMaskLayer, type ChartMaskShape, type ChartMaskPolygon, type ChartMaskAnnulus, type ResolvedChartMaterialLayers, type ResolvedChartMaskLayer, type ResolvedChartMaskShape } from "./facade/chart-material-layers.js";
|
|
224
237
|
export { EXPORT_JPEG_ENCODER_ID } from "./capture/export-jpeg.js";
|
|
@@ -228,6 +241,8 @@ export type { DngImportInput, ImportedDngRaw, ImportedDngCfa, ImportedDngBlackLe
|
|
|
228
241
|
export { parseLosslessJpeg, type LosslessJpegImage, type LosslessJpegLimits } from "./capture/lossless-jpeg.js";
|
|
229
242
|
export { PNG_ENCODER_ID, PNG_ENCODER_LIMITS, serializePngImage } from "./output/png-encoder.js";
|
|
230
243
|
export type { PngEncodeInput, PngColourEncoding, PngCicpPrimaries, PngCicpTransfer, PngMasteringDisplay, PngContentLightLevel } from "./output/png-encoder.js";
|
|
244
|
+
export { SIMULATE_CAPTURE_FAST_METHODS, type SimulateCaptureFastMethod } from "./facade/fast-methods.js";
|
|
245
|
+
export { DETAIL_LIMIT_LIMITS, calculateDetailLimit, type CalculateDetailLimitInput, type DetailLimit, type DetailLimitBasis, type DetailLimitCatalogueLens, type DetailLimitIdealLens, type DetailLimitOptics, type DetailLimitSampling, type DetailLimitSystem, type DetailLimitedBy, type DetailLimitingFactor } from "./optics/detail-limit.js";
|
|
231
246
|
declare global {
|
|
232
247
|
/**
|
|
233
248
|
* Minimal global AbortSignal type. It lets the published declarations type-check with
|
package/dist/index.js
CHANGED
|
@@ -82,9 +82,11 @@ export { calculateSensorReadoutTiming } from "./sensor/readout-timing.js";
|
|
|
82
82
|
export { calculateCaptureExposureWindows } from "./sensor/exposure-window.js";
|
|
83
83
|
export { assessReadoutExposureTimingLinkage, resolveElectronicRollingShutterExposureSchedule, createRollingShutterCaptureExposureSchedule, ELECTRONIC_ROLLING_SHUTTER_MODEL } from "./sensor/readout-exposure-linkage.js";
|
|
84
84
|
export { calculateCenteredCrop } from "./output/crop.js";
|
|
85
|
+
export { calculateCropToMatchFocalLength } from "./output/crop-to-match-focal-length.js";
|
|
85
86
|
export { calculateSubjectFramingCrop } from "./output/subject-framing-crop.js";
|
|
86
87
|
export { calculateActiveCaptureFieldOfView, calculateOutputFieldOfView, mapImagePlanePointToOrientedPhysicalUv, mapOrientedPhysicalUvToImagePlanePoint, resolveCaptureGeometry, transformNativeRasterPointToOriented, transformNativeRasterRectToOriented, transformNativeRasterVectorToOriented, transformOrientedRasterPointToNative, transformOrientedRasterRectToNative, transformOrientedRasterVectorToNative } from "./output/capture-geometry.js";
|
|
87
88
|
export { calculateIdealApertureGeometry } from "./optics/aperture.js";
|
|
89
|
+
export { calculateApertureDiameter } from "./optics/aperture-diameter.js";
|
|
88
90
|
export { calculateAiryDisk } from "./optics/diffraction.js";
|
|
89
91
|
export { calculateIdealPolygonDiffractionPsf, calculatePolygonPupilFraunhoferPsf } from "./optics/polygon-diffraction.js";
|
|
90
92
|
export { ZERNIKE_MAXIMUM_NOLL_INDEX, ZERNIKE_PUPIL_MAXIMUM_SAMPLES_ACROSS, calculateDefocusWavefront, createWavefrontPupilGrid, estimateMarechalStrehlRatio, evaluateZernikePolynomial, resolveZernikeNollOrder } from "./optics/zernike-wavefront.js";
|
|
@@ -156,6 +158,7 @@ export { calculateEnvironmentSensorPhotoSignal } from "./sensor/environment-phot
|
|
|
156
158
|
export { simulateEnvironmentSensorRawFrame } from "./capture/environment-raw-producer.js";
|
|
157
159
|
export { calculateProcessedSensorRaw, parseProcessedSensorRawInput } from "./capture/photographic-export.js";
|
|
158
160
|
export { calculatePrintPlan, calculatePrintSizeLimit, parsePrintPlanInput } from "./output/print-plan.js";
|
|
161
|
+
export { calculatePrintSizeLimitWithBlurAndNoise } from "./output/print-size-blur-noise.js";
|
|
159
162
|
export { PRINT_REGION_DETAIL_MODEL_VERSION, MAX_PRINT_DETAIL_REGION_SAMPLES, calculatePrintRegionDetail, parsePrintRegionDetailInput } from "./output/print-detail.js";
|
|
160
163
|
export { PRINT_REGION_STATISTICS_MODEL_VERSION, MAX_PRINT_REGION_STATISTICS_SAMPLES, calculatePrintRegionDifference, calculatePrintRegionNoise, parsePrintRegionDifferenceInput, parsePrintRegionNoiseInput } from "./output/print-region-statistics.js";
|
|
161
164
|
export { PRINT_CONTRAST_REFERENCE_MODEL_VERSION, PRINT_CONTRAST_REFERENCE_UPSTREAM_REVISION, calculatePrintContrastReference, parsePrintContrastReferenceInput } from "./output/print-contrast-reference.js";
|
|
@@ -185,17 +188,23 @@ export { SYNTHETIC_FILM_GRAIN_STREAM_ID, createBilateralFilterTask, createNonLoc
|
|
|
185
188
|
export { calculateSensorApertureRays } from "./optics/sensor-aperture-rays.js";
|
|
186
189
|
export { SIMULATE_CAPTURE_FACADE_VERSION, SIMULATE_CAPTURE_DEFAULT_ILLUMINANCE_LUX, SIMULATE_CAPTURE_COST_OPTIONS, SIMULATE_CAPTURE_METERING_MODES, simulateCapture, SIMULATE_CAPTURE_BOX_APERTURE_DEFAULT_SAMPLES, SIMULATE_CAPTURE_FAST_OPTIONS, simulateIdealReference, serializeSimulatedCaptureDngFromParts, SIMULATE_DISPLAY_VIEW_DEFAULT_SAMPLES_PER_AXIS } from "./facade/simulate-capture.js";
|
|
187
190
|
export { simulateCaptureFromParts } from "./facade/develop-joined-parts.js";
|
|
191
|
+
export { EXPOSURE_BUILD_UP_MAXIMUM_FRACTIONS, EXPOSURE_BUILD_UP_STREAM_BASE, simulateExposureBuildUp } from "./facade/exposure-build-up.js";
|
|
192
|
+
export { SENSOR_PROFILES, SENSOR_PROFILE_IDS, resolveSensorProfile } from "./equipment/sensor-profiles.js";
|
|
193
|
+
export { SENSOR_PROFILE_ISO_ANCHOR } from "./equipment/sensor-profile-body.js";
|
|
188
194
|
export { simulateDisplayView, prepareDisplayView, serializeDisplayViewCorrectionStates, bindDisplayViewCorrectionStates } from "./facade/simulate-display-view.js";
|
|
189
195
|
export { addJpegTextMetadata, addPngTextMetadata } from "./output/text-metadata.js";
|
|
190
196
|
export { GENERIC_THIRD_STOP_ISO_SETTINGS, GENERIC_THIRD_STOP_SHUTTER_SECONDS, GENERIC_WHOLE_STOP_ISO_SETTINGS } from "./equipment/generic-tier-assets.js";
|
|
191
197
|
export { GENERIC_PRIME_EQUIVALENT_FOCAL_LENGTHS_MM, GENERIC_PRIME_THIRD_STOP_F_NUMBERS, GENERIC_PRIME_MINIMUM_FOCUS, resolveGenericPrimeLens, calculateGenericPrimeMinimumFocusDistanceM } from "./equipment/generic-prime-lenses.js";
|
|
192
198
|
export { IDEAL_LENS_LIMITS } from "./equipment/ideal-lens.js";
|
|
193
199
|
export { GENERIC_LENS_CATALOGUE, GENERIC_LENS_IDS, GENERIC_LENS_SET_BASELINES, resolveGenericLens, simulateGenericLensFocusError } from "./equipment/generic-lens-catalogue.js";
|
|
194
|
-
export { createGenericLensCorrectionProfile, GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM } from "./output/generic-lens-corrections.js";
|
|
200
|
+
export { calculateChannelEffectiveDispersion, createGenericLensCorrectionProfile, GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM } from "./output/generic-lens-corrections.js";
|
|
201
|
+
export { calculateLateralColorFringe } from "./optics/generic-lens-lateral-color.js";
|
|
195
202
|
export { calculateChartFraming, calculateSubjectDistanceForFraming } from "./facade/subject-framing.js";
|
|
196
203
|
export { CHART_SCENE_PRESETS, CHART_SCENE_DEFAULTS, CHART_SPECTRAL_RANGE_NANOMETERS, resolveChartScene, calculateStepWedgeReflectances, calculatePointGridCenters, CHART_CONTINUOUS_LEVELS, calculateBarGroupTargets, calculateSlantedSquareEdges } from "./facade/chart-scenes.js";
|
|
197
204
|
export { COLOR_PATCH_SET_ID, COLOR_PATCH_SET_VERSION, COLOR_PATCH_IDS, COLOR_PATCH_WAVELENGTH_RANGE_NANOMETERS, getColorPatchSet, evaluateColorPatchReflectance } from "./facade/color-patches.js";
|
|
205
|
+
export { REPRESENTATIVE_LIGHT_SOURCE_SET_ID, REPRESENTATIVE_LIGHT_SOURCE_SET_VERSION, REPRESENTATIVE_LIGHT_SOURCE_IDS, REPRESENTATIVE_LIGHT_SOURCE_WAVELENGTH_RANGE_NANOMETERS, getRepresentativeLightSourceSet, createRepresentativeLightSourceSpectrum, createRepresentativeLightSourceIlluminant } from "./facade/representative-light-sources.js";
|
|
198
206
|
export { PHOTOPIC_MAXIMUM_LUMINOUS_EFFICACY_LM_PER_W, resolveCaptureIlluminant, createPlanarSceneRadianceProvider, CHART_SIZE_DEFAULT_SURROUND_REFLECTANCE, CALLER_MATERIAL_SCENE_MAX_MATERIALS } from "./facade/scene-radiance.js";
|
|
207
|
+
export { prepareImagePlaneScenes } from "./facade/image-plane-enable.js";
|
|
199
208
|
export { CHART_RADIANCE_BATCH_SCHEMA_VERSION, CHART_RADIANCE_BATCH_LIMITS, calculateChartRadianceBatchPlan, calculateChartRadianceBatch, mapEnvironmentDirectionsToChartPoints } from "./facade/chart-radiance-batch.js";
|
|
200
209
|
export { resolveChartMaterialLayers, CHART_MASK_INDEX_GRAIN, CHART_MATERIAL_LAYER_LIMITS } from "./facade/chart-material-layers.js";
|
|
201
210
|
export { EXPORT_JPEG_ENCODER_ID } from "./capture/export-jpeg.js";
|
|
@@ -203,4 +212,6 @@ export { DNG_IMPORT_SCHEMA_VERSION, DNG_IMPORT_LIMITS, parseDngRawImage } from "
|
|
|
203
212
|
export { NATIVE_RAW_DNG_SCHEMA_VERSION, serializeNativeRawDng } from "./capture/native-raw-dng.js";
|
|
204
213
|
export { parseLosslessJpeg } from "./capture/lossless-jpeg.js";
|
|
205
214
|
export { PNG_ENCODER_ID, PNG_ENCODER_LIMITS, serializePngImage } from "./output/png-encoder.js";
|
|
215
|
+
export { SIMULATE_CAPTURE_FAST_METHODS } from "./facade/fast-methods.js";
|
|
216
|
+
export { DETAIL_LIMIT_LIMITS, calculateDetailLimit } from "./optics/detail-limit.js";
|
|
206
217
|
//# sourceMappingURL=index.js.map
|