@photivra/engine 2.21.0 → 2.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/CHANGELOG.md +118 -1
  2. package/CITATION.cff +1 -1
  3. package/README.md +6 -6
  4. package/SECURITY.md +1 -1
  5. package/THIRD_PARTY.md +11 -0
  6. package/dist/capture/c2pa-embed.d.ts +116 -0
  7. package/dist/capture/c2pa-embed.js +493 -0
  8. package/dist/capture/c2pa-embed.js.map +1 -0
  9. package/dist/capture/dng-import.d.ts +73 -8
  10. package/dist/capture/dng-import.js +315 -80
  11. package/dist/capture/dng-import.js.map +1 -1
  12. package/dist/capture/dng-opcodes.d.ts +96 -0
  13. package/dist/capture/dng-opcodes.js +391 -0
  14. package/dist/capture/dng-opcodes.js.map +1 -0
  15. package/dist/capture/dng-profile-maps.d.ts +99 -0
  16. package/dist/capture/dng-profile-maps.js +381 -0
  17. package/dist/capture/dng-profile-maps.js.map +1 -0
  18. package/dist/capture/dng-stage-image.d.ts +23 -0
  19. package/dist/capture/dng-stage-image.js +65 -0
  20. package/dist/capture/dng-stage-image.js.map +1 -0
  21. package/dist/capture/jpeg-xl-tiles.d.ts +22 -0
  22. package/dist/capture/jpeg-xl-tiles.js +151 -0
  23. package/dist/capture/jpeg-xl-tiles.js.map +1 -0
  24. package/dist/capture/lossy-jpeg.d.ts +17 -0
  25. package/dist/capture/lossy-jpeg.js +369 -0
  26. package/dist/capture/lossy-jpeg.js.map +1 -0
  27. package/dist/capture/native-raw-development.d.ts +2 -1
  28. package/dist/capture/native-raw-development.js.map +1 -1
  29. package/dist/color/neighbor-highlight-reconstruction.d.ts +66 -0
  30. package/dist/color/neighbor-highlight-reconstruction.js +234 -0
  31. package/dist/color/neighbor-highlight-reconstruction.js.map +1 -0
  32. package/dist/color/sensor-color-development.d.ts +5 -0
  33. package/dist/color/sensor-color-development.js +7 -1
  34. package/dist/color/sensor-color-development.js.map +1 -1
  35. package/dist/color/spectral-spikiness.d.ts +11 -0
  36. package/dist/color/spectral-spikiness.js +23 -0
  37. package/dist/color/spectral-spikiness.js.map +1 -0
  38. package/dist/core/execution-error.d.ts +21 -0
  39. package/dist/core/execution-error.js +12 -0
  40. package/dist/core/execution-error.js.map +1 -0
  41. package/dist/core/version.d.ts +1 -1
  42. package/dist/core/version.js +1 -1
  43. package/dist/core/version.js.map +1 -1
  44. package/dist/facade/catalogue-lens-signal.d.ts +26 -1
  45. package/dist/facade/catalogue-lens-signal.js +25 -7
  46. package/dist/facade/catalogue-lens-signal.js.map +1 -1
  47. package/dist/facade/diffraction-provider.d.ts +1 -1
  48. package/dist/facade/diffraction-provider.js +4 -4
  49. package/dist/facade/diffraction-provider.js.map +1 -1
  50. package/dist/facade/display-view-gpu-session.js +38 -6
  51. package/dist/facade/display-view-gpu-session.js.map +1 -1
  52. package/dist/facade/display-view-gpu.d.ts +13 -5
  53. package/dist/facade/display-view-gpu.js.map +1 -1
  54. package/dist/facade/display-view-normal.d.ts +15 -0
  55. package/dist/facade/display-view-normal.js +44 -0
  56. package/dist/facade/display-view-normal.js.map +1 -0
  57. package/dist/facade/display-view-rendering.d.ts +97 -0
  58. package/dist/facade/display-view-rendering.js +598 -0
  59. package/dist/facade/display-view-rendering.js.map +1 -0
  60. package/dist/facade/display-view.d.ts +37 -65
  61. package/dist/facade/display-view.js +147 -476
  62. package/dist/facade/display-view.js.map +1 -1
  63. package/dist/facade/expected-signal-setup.js +2 -2
  64. package/dist/facade/expected-signal-setup.js.map +1 -1
  65. package/dist/facade/fast-methods.d.ts +1 -1
  66. package/dist/facade/fast-methods.js +37 -8
  67. package/dist/facade/fast-methods.js.map +1 -1
  68. package/dist/facade/generic-lens-capture.d.ts +1 -1
  69. package/dist/facade/generic-lens-capture.js +1 -1
  70. package/dist/facade/generic-lens-capture.js.map +1 -1
  71. package/dist/facade/image-plane.js +41 -10
  72. package/dist/facade/image-plane.js.map +1 -1
  73. package/dist/facade/on-demand-kits.d.ts +14 -0
  74. package/dist/facade/on-demand-kits.js +36 -0
  75. package/dist/facade/on-demand-kits.js.map +1 -0
  76. package/dist/facade/opt-in-kit.d.ts +9 -0
  77. package/dist/facade/opt-in-kit.js +11 -0
  78. package/dist/facade/opt-in-kit.js.map +1 -0
  79. package/dist/facade/quality-kit.d.ts +21 -0
  80. package/dist/facade/quality-kit.js +23 -0
  81. package/dist/facade/quality-kit.js.map +1 -0
  82. package/dist/facade/quality-paths.d.ts +22 -0
  83. package/dist/facade/quality-paths.js +44 -0
  84. package/dist/facade/quality-paths.js.map +1 -0
  85. package/dist/facade/scene-radiance.d.ts +18 -2
  86. package/dist/facade/scene-radiance.js +6 -4
  87. package/dist/facade/scene-radiance.js.map +1 -1
  88. package/dist/facade/simulate-capture.d.ts +32 -13
  89. package/dist/facade/simulate-capture.js +162 -69
  90. package/dist/facade/simulate-capture.js.map +1 -1
  91. package/dist/facade/simulate-display-view.d.ts +10 -12
  92. package/dist/facade/simulate-display-view.js +57 -48
  93. package/dist/facade/simulate-display-view.js.map +1 -1
  94. package/dist/gpu/display-view-gpu-renderer.d.ts +43 -0
  95. package/dist/gpu/display-view-gpu-renderer.js +134 -0
  96. package/dist/gpu/display-view-gpu-renderer.js.map +1 -0
  97. package/dist/gpu/display-view-image-material-module.d.ts +3 -2
  98. package/dist/gpu/display-view-image-material-module.js +25 -3
  99. package/dist/gpu/display-view-image-material-module.js.map +1 -1
  100. package/dist/gpu/display-view-image-quality.d.ts +43 -1
  101. package/dist/gpu/display-view-image-quality.js +256 -11
  102. package/dist/gpu/display-view-image-quality.js.map +1 -1
  103. package/dist/gpu/display-view-quality-gpu.d.ts +13 -64
  104. package/dist/gpu/display-view-quality-gpu.js +60 -249
  105. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  106. package/dist/gpu/display-view-speed-gpu.d.ts +16 -16
  107. package/dist/gpu/display-view-speed-gpu.js +50 -12
  108. package/dist/gpu/display-view-speed-gpu.js.map +1 -1
  109. package/dist/gpu/image-kernel-accelerator.js +3 -0
  110. package/dist/gpu/image-kernel-accelerator.js.map +1 -1
  111. package/dist/gpu/image-kernel-execution.d.ts +2 -13
  112. package/dist/gpu/image-kernel-execution.js +2 -10
  113. package/dist/gpu/image-kernel-execution.js.map +1 -1
  114. package/dist/gpu/wgsl-display-view-coupled-stub.d.ts +8 -0
  115. package/dist/gpu/wgsl-display-view-coupled-stub.js +21 -0
  116. package/dist/gpu/wgsl-display-view-coupled-stub.js.map +1 -0
  117. package/dist/gpu/wgsl-display-view-coupled.d.ts +88 -0
  118. package/dist/gpu/wgsl-display-view-coupled.js +353 -0
  119. package/dist/gpu/wgsl-display-view-coupled.js.map +1 -0
  120. package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +4 -9
  121. package/dist/gpu/wgsl-display-view-quality-kernel.js +109 -111
  122. package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
  123. package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +1 -41
  124. package/dist/gpu/wgsl-display-view-speed-kernel.js +71 -8
  125. package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
  126. package/dist/index.d.ts +11 -3
  127. package/dist/index.js +9 -1
  128. package/dist/index.js.map +1 -1
  129. package/dist/output/camera-channel-response.d.ts +50 -0
  130. package/dist/output/camera-channel-response.js +69 -0
  131. package/dist/output/camera-channel-response.js.map +1 -0
  132. package/dist/output/native-capture-sdr.js +5 -2
  133. package/dist/output/native-capture-sdr.js.map +1 -1
  134. package/dist/output/sdr-rendering.d.ts +18 -1
  135. package/dist/output/sdr-rendering.js +39 -2
  136. package/dist/output/sdr-rendering.js.map +1 -1
  137. package/dist/sensor/native-sensor-report.d.ts +10 -0
  138. package/dist/sensor/native-sensor-report.js +16 -0
  139. package/dist/sensor/native-sensor-report.js.map +1 -0
  140. package/dist/sensor/sensor-characteristics.d.ts +81 -13
  141. package/dist/sensor/sensor-characteristics.js +10 -6
  142. package/dist/sensor/sensor-characteristics.js.map +1 -1
  143. package/docs/API_REFERENCE.md +117 -4
  144. package/docs/QUICK_START.md +37 -8
  145. package/docs/USAGE.md +104 -22
  146. package/docs/api/capture-c2pa-embed.md +177 -0
  147. package/docs/api/capture-dng-import.md +86 -10
  148. package/docs/api/capture-dng-opcodes.md +93 -0
  149. package/docs/api/capture-dng-profile-maps.md +141 -0
  150. package/docs/api/capture-dng-stage-image.md +43 -0
  151. package/docs/api/capture-jpeg-xl-tiles.md +33 -0
  152. package/docs/api/capture-lossy-jpeg.md +41 -0
  153. package/docs/api/capture-native-raw-development.md +2 -1
  154. package/docs/api/core-execution-error.md +43 -0
  155. package/docs/api/core-version.md +1 -1
  156. package/docs/api/exports.json +255 -5
  157. package/docs/api/facade-display-view-gpu.md +5 -2
  158. package/docs/api/facade-display-view.md +11 -15
  159. package/docs/api/facade-fast-methods.md +38 -9
  160. package/docs/api/facade-quality-paths.md +24 -0
  161. package/docs/api/facade-scene-radiance.md +1 -1
  162. package/docs/api/facade-simulate-capture.md +24 -7
  163. package/docs/api/facade-simulate-display-view.md +10 -12
  164. package/docs/api/gpu-image-kernel-execution.md +0 -36
  165. package/docs/api/output-camera-channel-response.md +55 -0
  166. package/docs/api/output-sdr-rendering.md +6 -1
  167. package/docs/api/sensor-sensor-characteristics.md +54 -2
  168. package/llms.txt +1 -0
  169. package/package.json +6 -5
@@ -37,12 +37,6 @@ export declare const DISPLAY_VIEW_QUALITY_FLAG: Readonly<{
37
37
  materialUncertain: 1;
38
38
  /** A site the pixel read lies outside the band's site window (a host geometry error; recompute). */
39
39
  siteOutsideWindow: 2;
40
- /** The correction needed a grid state the table does not hold (recompute, or compute the state and dispatch again). */
41
- stateMissing: 4;
42
- /** A sample's pixel variance lies within its bound of the correction threshold (recompute). */
43
- thresholdTie: 8;
44
- /** Informational: the pixel's expected value includes the low-signal correction. */
45
- corrected: 16;
46
40
  /**
47
41
  * #457: the reference takes AHD's choice on the noise-free mosaic (one candidate, or their average on a tie), which the kernel
48
42
  * does not compute; it renders the average. The pixel is flagged (recompute) when Σ_j a_j·½|h(H) − h(V)| of some component
@@ -52,7 +46,7 @@ export declare const DISPLAY_VIEW_QUALITY_FLAG: Readonly<{
52
46
  /** #533: a real pixel's saturation is undecided (the host computes the display pixel's count with the reference; its samples stay). */
53
47
  highlightUndecided: 64;
54
48
  /** The bits that require the host's recomputation. */
55
- recompute: 47;
49
+ recompute: 35;
56
50
  }>;
57
51
  /** #533: flag words per display pixel: the flags, then the 36-bit mask of saturated real pixels. */
58
52
  export declare const DISPLAY_VIEW_QUALITY_FLAG_WORDS = 3;
@@ -62,8 +56,6 @@ export declare const DISPLAY_VIEW_QUALITY_FLAG_WORDS = 3;
62
56
  * design tolerance, not a measurement: 2^-10 σ is a tenth of the 0.01 σ to which the float32 tests hold the GPU to the reference.
63
57
  */
64
58
  export declare const DISPLAY_VIEW_QUALITY_CHOICE_SIGMA: number;
65
- /** Words of the grid-key bitmap: one bit per grid key (AHD_KEY_LEVELS³ keys). */
66
- export declare const DISPLAY_VIEW_QUALITY_BITMAP_WORDS: number;
67
59
  /**
68
60
  * A site whose uncertain lattice points (the material module's flag) could move its electrons by more than this fraction of
69
61
  * their value is flagged for host recomputation; a smaller uncertainty enters the site's bound instead (the tap weights times
@@ -120,6 +112,9 @@ export declare const DISPLAY_VIEW_QUALITY_SITES_WGSL: string;
120
112
  */
121
113
  export declare const DISPLAY_VIEW_QUALITY_SITES_BLOCKED_WGSL: string;
122
114
  /** Pass 3: the display pixels (see the module comment). */
115
+ export declare const DISPLAY_VIEW_QUALITY_PIXELS_BODY_WGSL: string;
116
+ /** The pixel pass (`DISPLAY_VIEW_QUALITY_PIXELS_BODY_WGSL`) with the coupled steps' text: the stub by default, the coupled steps on demand (#593). */
117
+ export declare function assembleDisplayViewQualityPixelsWgsl(coupledWgsl?: string): string;
123
118
  export declare const DISPLAY_VIEW_QUALITY_PIXELS_WGSL: string;
124
119
  /** The lattice pass with a material module appended (`fn material_at(p: vec2<f32>) -> u32`, `var<private> material_uncertain: bool`). */
125
120
  export declare function assembleDisplayViewQualityLatticeWgsl(materialModuleWgsl: string): string;
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  /**
3
3
  * WGSL kernels of the display view's Quality path on the GPU (#479): the exact area mean with diffraction kernels, the
4
- * anti-aliasing filter's spots, the AHD candidates and the low-signal correction, in three passes over one band of display
4
+ * anti-aliasing filter's spots and the AHD candidates, in three passes over one band of display
5
5
  * rows (docs/WEBGPU.md, "Display view (Quality) on the GPU"; the float64 reference is `renderDisplayView` with
6
6
  * `createDisplayViewExpectedSignal`, facade/display-view.ts and facade/expected-signal.ts):
7
7
  *
@@ -21,9 +21,7 @@
21
21
  * camera-channel covariance), white balance and the highlight clip, the colour matrix, the tone curve and the clip to
22
22
  * [0, 1] with the skewness term, the candidates' average, the Stein covariance with the closed-form B_c, the independent
23
23
  * residual, AHD's choice variance ¼·Var(H − V), the flag for AHD's choice on the noise-free mosaic, which the reference takes and
24
- * the kernel does not (#457), and the low-signal correction interpolated trilinearly between the grid
25
- * states of a table the host uploaded (the states themselves are computed on the host, #447; the kernel records every
26
- * grid key it needs in a bitmap and flags a display pixel whose state the table lacks).
24
+ * the kernel does not (#457). 2.22.0: there is no low-signal correction (docs/DISPLAY_VIEW.md, "AHD at low signal").
27
25
  *
28
26
  * **Highlights (#533).** The site pass records whether each site is certainly below white, certainly at or above it, or
29
27
  * undecided (`clip_state`, from the site's mean and variance and their running bounds: certain only beyond twice the reference's
@@ -50,8 +48,8 @@
50
48
  * trigonometric built-in).
51
49
  */
52
50
  import { DISPLAY_VIEW_CLIP_MEAN_U, DISPLAY_VIEW_CLIP_VARIANCE_U, DISPLAY_VIEW_REINHARD_MEAN_U, DISPLAY_VIEW_REINHARD_VARIANCE_U } from "./wgsl-display-view-speed-kernel.js";
53
- import { AHD_KEY_FLOOR, AHD_KEY_LEVELS, AHD_KEY_OCTAVES, AHD_KEY_STEPS } from "../facade/display-view.js";
54
51
  import { EXACT_SUM_WGSL } from "./wgsl-exact-sum.js";
52
+ import { DISPLAY_VIEW_COUPLED_STUB_WGSL } from "./wgsl-display-view-coupled-stub.js";
55
53
  export const DISPLAY_VIEW_QUALITY_WORKGROUP_SIZE = 64;
56
54
  /** Largest footprint per axis (real pixels), as the Speed kernel. */
57
55
  export const DISPLAY_VIEW_QUALITY_MAXIMUM_PIXELS_PER_AXIS = 6;
@@ -92,12 +90,7 @@ export const DISPLAY_VIEW_QUALITY_FLAG = /* @__PURE__ */ Object.freeze({
92
90
  materialUncertain: 1,
93
91
  /** A site the pixel read lies outside the band's site window (a host geometry error; recompute). */
94
92
  siteOutsideWindow: 2,
95
- /** The correction needed a grid state the table does not hold (recompute, or compute the state and dispatch again). */
96
- stateMissing: 4,
97
- /** A sample's pixel variance lies within its bound of the correction threshold (recompute). */
98
- thresholdTie: 8,
99
- /** Informational: the pixel's expected value includes the low-signal correction. */
100
- corrected: 16,
93
+ // Bits 4, 8 and 16 (the low-signal correction's state, threshold and applied flags) are unused since 2.22.0.
101
94
  /**
102
95
  * #457: the reference takes AHD's choice on the noise-free mosaic (one candidate, or their average on a tie), which the kernel
103
96
  * does not compute; it renders the average. The pixel is flagged (recompute) when Σ_j a_j·½|h(H) − h(V)| of some component
@@ -107,7 +100,7 @@ export const DISPLAY_VIEW_QUALITY_FLAG = /* @__PURE__ */ Object.freeze({
107
100
  /** #533: a real pixel's saturation is undecided (the host computes the display pixel's count with the reference; its samples stay). */
108
101
  highlightUndecided: 64,
109
102
  /** The bits that require the host's recomputation. */
110
- recompute: 47
103
+ recompute: 35
111
104
  });
112
105
  /** #533: flag words per display pixel: the flags, then the 36-bit mask of saturated real pixels. */
113
106
  export const DISPLAY_VIEW_QUALITY_FLAG_WORDS = 3;
@@ -117,8 +110,6 @@ export const DISPLAY_VIEW_QUALITY_FLAG_WORDS = 3;
117
110
  * design tolerance, not a measurement: 2^-10 σ is a tenth of the 0.01 σ to which the float32 tests hold the GPU to the reference.
118
111
  */
119
112
  export const DISPLAY_VIEW_QUALITY_CHOICE_SIGMA = 2 ** -10;
120
- /** Words of the grid-key bitmap: one bit per grid key (AHD_KEY_LEVELS³ keys). */
121
- export const DISPLAY_VIEW_QUALITY_BITMAP_WORDS = Math.ceil(AHD_KEY_LEVELS ** 3 / 32);
122
113
  /**
123
114
  * A site whose uncertain lattice points (the material module's flag) could move its electrons by more than this fraction of
124
115
  * their value is flagged for host recomputation; a smaller uncertainty enters the site's bound instead (the tap weights times
@@ -156,11 +147,11 @@ count: u32, row0: u32, region_w: u32, region_x: u32,
156
147
  region_y: u32, margin: u32, native_w: u32, native_h: u32,
157
148
  columns: u32, tone: u32, reach: u32, candidates: u32,
158
149
  site_x0: i32, site_y0: i32, site_w: u32, site_h: u32,
159
- correction: u32, state_count: u32, taps: u32, groups: u32,
150
+ unused_16: u32, unused_17: u32, taps: u32, groups: u32,
160
151
  lattice_total: u32, gain_at_clip0: u32, gain_at_clip1: u32, gain_at_clip2: u32,
161
152
  k0: f32, k1: f32, k2: f32, reach2: f32,
162
153
  dark0: f32, dark1: f32, dark2: f32, clip_level: f32,
163
- c0_0: f32, c0_1: f32, c0_2: f32, threshold: f32,
154
+ c0_0: f32, c0_1: f32, c0_2: f32, unused_35: f32,
164
155
  g0: f32, g1: f32, g2: f32, scale_u: f32,
165
156
  m00: f32, m01: f32, m02: f32, m10: f32,
166
157
  m11: f32, m12: f32, m20: f32, m21: f32,
@@ -531,30 +522,26 @@ write_site(i, c, e, de, flag);
531
522
  }
532
523
  `;
533
524
  /** Pass 3: the display pixels (see the module comment). */
534
- export const DISPLAY_VIEW_QUALITY_PIXELS_WGSL = /* wgsl */ `${DISPLAY_VIEW_QUALITY_COMMON_WGSL}
535
- const KEY_LEVELS: u32 = ${AHD_KEY_LEVELS}u;
536
- const KEY_STEPS: f32 = ${literal(AHD_KEY_STEPS)};
537
- const KEY_OCTAVES: f32 = ${literal(AHD_KEY_OCTAVES)};
538
- const KEY_FLOOR: f32 = ${literal(AHD_KEY_FLOOR)};
539
- const KEY_TOP: u32 = ${AHD_KEY_OCTAVES * AHD_KEY_STEPS - 1}u;
525
+ /*
526
+ * 2.22.0: in the luminance branch the nested loops read the colour matrix rows from one local array (`mm`) instead of calling
527
+ * `m_of` (a `switch`): SwiftShader's compiler ended the GPU process on the `switch` inside those loops (after about 44 s). The
528
+ * values are the same (docs/WEBGPU.md, "Coupled rendering steps").
529
+ */
530
+ export const DISPLAY_VIEW_QUALITY_PIXELS_BODY_WGSL = /* wgsl */ `${DISPLAY_VIEW_QUALITY_COMMON_WGSL}
540
531
  const CAND_BASE: u32 = ${DISPLAY_VIEW_QUALITY_AUX.candidates}u;
541
532
  const CAND_STRIDE: u32 = ${CANDIDATE_PHASE_STRIDE}u;
542
533
  const FLAG_UNCERTAIN: u32 = ${DISPLAY_VIEW_QUALITY_FLAG.materialUncertain}u;
543
534
  const FLAG_OUTSIDE: u32 = ${DISPLAY_VIEW_QUALITY_FLAG.siteOutsideWindow}u;
544
- const FLAG_STATE: u32 = ${DISPLAY_VIEW_QUALITY_FLAG.stateMissing}u;
545
- const FLAG_TIE: u32 = ${DISPLAY_VIEW_QUALITY_FLAG.thresholdTie}u;
546
- const FLAG_CORRECTED: u32 = ${DISPLAY_VIEW_QUALITY_FLAG.corrected}u;
547
535
  const FLAG_CHOICE: u32 = ${DISPLAY_VIEW_QUALITY_FLAG.ahdChoice}u;
548
536
  const FLAG_HIGHLIGHT: u32 = ${DISPLAY_VIEW_QUALITY_FLAG.highlightUndecided}u;
549
537
  const CHOICE_SIGMA: f32 = ${literal(DISPLAY_VIEW_QUALITY_CHOICE_SIGMA)};
550
538
  @group(0) @binding(1) var<storage, read> aux: array<f32>;
551
539
  @group(0) @binding(2) var<storage, read> geometry: array<f32>;
552
540
  @group(0) @binding(3) var<storage, read> sites: array<f32>;
553
- @group(0) @binding(4) var<storage, read> state_keys: array<i32>;
554
- @group(0) @binding(5) var<storage, read> state_values: array<f32>;
555
- @group(0) @binding(6) var<storage, read_write> bitmap: array<atomic<u32>>;
556
- @group(0) @binding(7) var<storage, read_write> out: array<f32>;
557
- @group(0) @binding(8) var<storage, read_write> flags: array<u32>;
541
+ @group(0) @binding(4) var<storage, read_write> out: array<f32>;
542
+ @group(0) @binding(5) var<storage, read_write> flags: array<u32>;
543
+
544
+ fn cp_k(i: u32) -> f32 { return aux[${DISPLAY_VIEW_QUALITY_AUX.size}u + i]; }
558
545
 
559
546
  var<private> pixel_flags: u32;
560
547
  ${REINHARD_WGSL}
@@ -571,66 +558,6 @@ return o;
571
558
  }
572
559
 
573
560
  fn clip_bits(o: u32) -> u32 { return (bitcast<u32>(sites[o + 6u]) >> 1u) & 3u; }
574
-
575
- fn find_state(key: i32) -> u32 {
576
- var lo = 0u; var hi = params.state_count;
577
- while (lo < hi) {
578
- let mid = (lo + hi) / 2u;
579
- if (state_keys[mid] < key) { lo = mid + 1u; } else { hi = mid; }
580
- }
581
- if (lo < params.state_count && state_keys[lo] == key) { return lo; }
582
- return params.state_count;
583
- }
584
-
585
-
586
-
587
- fn flat_correction(m0: vec2<f32>, m1: vec2<f32>, m2: vec2<f32>, corr: ptr<function, array<vec2<f32>, 3>>) {
588
- var base: array<u32, 3>; var frac: array<f32, 3>; var dg: array<f32, 3>;
589
- for (var i = 0u; i < 3u; i = i + 1u) {
590
- var mi = m0; if (i == 1u) { mi = m1; } if (i == 2u) { mi = m2; }
591
- let clamped = clamp(mi.x, KEY_FLOOR, 1.0);
592
- let g = (log2(clamped) + KEY_OCTAVES) * KEY_STEPS;
593
- let b = min(u32(max(floor(g), 0.0)), KEY_TOP);
594
- base[i] = b; frac[i] = g - f32(b);
595
-
596
- var slope = 0.0; if (mi.x > KEY_FLOOR && mi.x < 1.0) { slope = 1.4426950408889634 * mi.y / clamped; }
597
- dg[i] = KEY_STEPS * (slope + 4.76837158203125e-7 + 36.0 * E) + 2.0 * E * (g + 1.0);
598
- }
599
- var values: array<f32, 24>;
600
- var missing = false;
601
- for (var corner = 0u; corner < 8u; corner = corner + 1u) {
602
- let i0 = base[0] + (corner & 1u); let i1 = base[1] + ((corner >> 1u) & 1u); let i2 = base[2] + ((corner >> 2u) & 1u);
603
- let key = i32((i0 * KEY_LEVELS + i1) * KEY_LEVELS + i2);
604
- var weight = 1.0;
605
- for (var i = 0u; i < 3u; i = i + 1u) { weight = weight * select(1.0 - frac[i], frac[i], ((corner >> i) & 1u) == 1u); }
606
- if (weight == 0.0) { for (var c = 0u; c < 3u; c = c + 1u) { values[corner * 3u + c] = 0.0; } continue; }
607
- atomicOr(&bitmap[u32(key) / 32u], 1u << (u32(key) % 32u));
608
- let at = find_state(key);
609
- if (at >= params.state_count) { missing = true; continue; }
610
- for (var c = 0u; c < 3u; c = c + 1u) { values[corner * 3u + c] = state_values[at * 3u + c]; }
611
- }
612
- if (missing) { pixel_flags = pixel_flags | FLAG_STATE; for (var c = 0u; c < 3u; c = c + 1u) { (*corr)[c] = vec2<f32>(0.0, 0.0); } return; }
613
- for (var c = 0u; c < 3u; c = c + 1u) {
614
- var sum = 0.0; var mag = 0.0;
615
- for (var corner = 0u; corner < 8u; corner = corner + 1u) {
616
- var weight = 1.0;
617
- for (var i = 0u; i < 3u; i = i + 1u) { weight = weight * select(1.0 - frac[i], frac[i], ((corner >> i) & 1u) == 1u); }
618
- sum = sum + weight * values[corner * 3u + c];
619
- mag = mag + abs(weight * values[corner * 3u + c]);
620
- }
621
-
622
- var slope_term = 0.0;
623
- for (var i = 0u; i < 3u; i = i + 1u) {
624
- var largest = 0.0;
625
- for (var corner = 0u; corner < 8u; corner = corner + 1u) {
626
- if (((corner >> i) & 1u) == 1u) { continue; }
627
- largest = max(largest, abs(values[(corner | (1u << i)) * 3u + c] - values[corner * 3u + c]));
628
- }
629
- slope_term = slope_term + dg[i] * largest;
630
- }
631
- (*corr)[c] = vec2<f32>(sum, slope_term + 12.0 * E * mag);
632
- }
633
- }
634
561
  @compute @workgroup_size(${DISPLAY_VIEW_QUALITY_WORKGROUP_SIZE})
635
562
  fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) wg: vec3<u32>) {
636
563
  let i = gid.x + gid.y * wg.x * ${DISPLAY_VIEW_QUALITY_WORKGROUP_SIZE}u;
@@ -647,6 +574,9 @@ let ny = bitcast<u32>(geometry[row + 1u]);
647
574
  let margin = i32(params.margin);
648
575
  let reinhard = params.tone == 1u;
649
576
  let count = params.candidates;
577
+
578
+ var cp_used = false;
579
+ var cp_a: array<vec2<f32>, 9>;
650
580
  let share = select(1.0, 0.5, count == 2u);
651
581
 
652
582
  let xb_even = geometry[col + 8u]; let xb_odd = geometry[col + 9u];
@@ -711,8 +641,6 @@ let bit = j * nx + ii;
711
641
  if (bit < 32u) { mask0 = mask0 | (1u << bit); } else { mask1 = mask1 | (1u << (bit - 32u)); }
712
642
  } else if ((clip_any & 2u) != 0u) { undecided = true; }
713
643
  var e_mean = array<vec2<f32>, 3>(vec2<f32>(0.0), vec2<f32>(0.0), vec2<f32>(0.0));
714
- var cm_average = array<vec2<f32>, 3>(vec2<f32>(0.0), vec2<f32>(0.0), vec2<f32>(0.0));
715
- var pixel_variance = vec2<f32>(0.0, 0.0);
716
644
  var bs: array<vec2<f32>, 3>; var hs: array<vec2<f32>, 3>;
717
645
  var hv: array<vec2<f32>, 3>;
718
646
 
@@ -739,17 +667,26 @@ cm[0] = b_add(cm[0], b_scale(sm, w0)); cm[1] = b_add(cm[1], b_scale(sm, w1)); cm
739
667
  C[0] = b_add(C[0], b_scale(sv, w0 * w0)); C[1] = b_add(C[1], b_scale(sv, w0 * w1)); C[2] = b_add(C[2], b_scale(sv, w0 * w2));
740
668
  C[3] = b_add(C[3], b_scale(sv, w1 * w1)); C[4] = b_add(C[4], b_scale(sv, w1 * w2)); C[5] = b_add(C[5], b_scale(sv, w2 * w2));
741
669
  }
742
- for (var c = 0u; c < 3u; c = c + 1u) { if (exact[c]) { cm[c].y = 0.0; } cm_average[c] = b_add(cm_average[c], b_scale(cm[c], share)); }
670
+ for (var c = 0u; c < 3u; c = c + 1u) { if (exact[c]) { cm[c].y = 0.0; } }
671
+
672
+
673
+ var cp_chain_run = false;
674
+ if (cp_on() && cp_reconstruct()) {
675
+ let reach = cp_reconstruct_reach(vec3<f32>(cm[0].x, cm[1].x, cm[2].x), vec3<f32>(C[0].x, C[3].x, C[5].x));
676
+ if (reach == 2u) { pixel_flags = pixel_flags | FLAG_UNCERTAIN; }
677
+ cp_chain_run = reach >= 1u;
678
+ }
679
+ let cp_unclipped = cp_on() && cp_reconstruct();
743
680
 
744
681
 
745
682
  var bm: array<vec2<f32>, 3>; var bv: array<vec2<f32>, 3>;
746
683
  for (var c = 0u; c < 3u; c = c + 1u) {
747
684
  let gc = b_rounded(g_of(c));
748
685
  var um = b_mul(gc, cm[c]);
749
- if (exact[c] && cm[c].x == 1.0 && gain_at_clip(c)) { um = vec2<f32>(params.clip_level, 0.0); }
686
+ if (exact[c] && cm[c].x == 1.0 && gain_at_clip(c) && !cp_unclipped) { um = vec2<f32>(params.clip_level, 0.0); }
750
687
  let uv = b_mul(b_mul(gc, gc), C[select(select(0u, 3u, c == 1u), 5u, c == 2u)]);
751
688
  let gap = params.clip_level - um.x;
752
- if (gap > 0.0 && gap * gap > params.reach2 * uv.x) { bm[c] = um; bv[c] = uv; bs[c] = gc; }
689
+ if (cp_unclipped || (gap > 0.0 && gap * gap > params.reach2 * uv.x)) { bm[c] = um; bv[c] = uv; bs[c] = gc; }
753
690
  else { let clipped = upper_clip(um, uv, params.clip_level); bm[c] = clipped.mean; bv[c] = clipped.variance; bs[c] = b_mul(gc, clipped.slope); }
754
691
  }
755
692
 
@@ -785,16 +722,75 @@ if (variance.x > 0.0) { skew = b_div(third, b_mul(variance, b_sqrt(variance)));
785
722
  moments = unit_clip(mean, variance, skew);
786
723
  }
787
724
  hm[comp] = moments.mean; hv[comp] = moments.variance; hs[comp] = moments.slope;
788
- h_cand[d * 3u + comp] = moments.mean;
789
- e_mean[comp] = b_add(e_mean[comp], b_scale(moments.mean, share));
790
- pixel_variance = vec2<f32>(max(pixel_variance.x, moments.variance.x), max(pixel_variance.y, moments.variance.y));
791
725
  }
792
726
 
793
727
  var an: array<vec2<f32>, 9>;
728
+ cp_used = false;
729
+ if (cp_on()) {
730
+ if (!cp_chain_run && cp_luminance()) {
731
+ var mu = vec3<f32>(0.0); var dmu = vec3<f32>(0.0); var dsv = vec3<f32>(0.0);
732
+ var srow = array<vec3<f32>, 3>(vec3<f32>(0.0), vec3<f32>(0.0), vec3<f32>(0.0));
733
+ var cc = array<f32, 9>(C[0].x, C[1].x, C[2].x, C[1].x, C[3].x, C[4].x, C[2].x, C[4].x, C[5].x);
734
+ var mm = array<vec3<f32>, 3>(vec3<f32>(params.m00, params.m01, params.m02), vec3<f32>(params.m10, params.m11, params.m12), vec3<f32>(params.m20, params.m21, params.m22));
735
+ for (var r = 0u; r < 3u; r = r + 1u) {
736
+ mu[r] = mm[r][0] * bm[0].x + mm[r][1] * bm[1].x + mm[r][2] * bm[2].x;
737
+ dmu[r] = abs(mm[r][0]) * bm[0].y + abs(mm[r][1]) * bm[1].y + abs(mm[r][2]) * bm[2].y;
738
+ dsv[r] = mm[r][0] * mm[r][0] * bv[0].y + mm[r][1] * mm[r][1] * bv[1].y + mm[r][2] * mm[r][2] * bv[2].y;
739
+ for (var q = 0u; q < 3u; q = q + 1u) {
740
+ var v = 0.0;
741
+ for (var a = 0u; a < 3u; a = a + 1u) { for (var b = 0u; b < 3u; b = b + 1u) {
742
+ var bab = bv[a].x; if (a != b) { bab = bs[a].x * bs[b].x * cc[a * 3u + b]; }
743
+ v = v + mm[r][a] * mm[q][b] * bab;
744
+ } }
745
+ srow[r][q] = v;
746
+ }
747
+ }
748
+ let t = cp_tone(mu, srow[0], srow[1], srow[2], dmu, dsv);
749
+ if (t.flag) { pixel_flags = pixel_flags | FLAG_UNCERTAIN; }
750
+ if (cp_desaturate() && t.top) { cp_chain_run = true; }
751
+ else {
752
+ let rows = array<vec3<f32>, 3>(t.a0, t.a1, t.a2);
753
+ for (var comp = 0u; comp < 3u; comp = comp + 1u) {
754
+ hm[comp] = vec2<f32>(t.hm[comp], t.bm[comp]); hv[comp] = vec2<f32>(t.hv[comp], t.bv[comp]);
755
+ for (var c = 0u; c < 3u; c = c + 1u) {
756
+ let jmc = rows[comp].x * m_of(0u, c) + rows[comp].y * m_of(1u, c) + rows[comp].z * m_of(2u, c);
757
+ let ajm = abs(rows[comp].x * m_of(0u, c)) + abs(rows[comp].y * m_of(1u, c)) + abs(rows[comp].z * m_of(2u, c));
758
+ let value = jmc * bs[c].x;
759
+ an[comp * 3u + c] = vec2<f32>(value, ajm * bs[c].y + abs(value) * (t.ju + 4.0 * E));
760
+ }
761
+ }
762
+ cp_used = true;
763
+ }
764
+ } else if (!cp_chain_run && cp_desaturate() && !reinhard) {
765
+ for (var comp = 0u; comp < 3u; comp = comp + 1u) {
766
+ let top = hm[comp].x + CLIP_REACH * sqrt(hv[comp].x);
767
+ if (hm[comp].x > 0.0 && top >= 0.999) { cp_chain_run = true; }
768
+ if (hm[comp].x > 0.0 && hm[comp].x - 2.0 * hm[comp].y < 0.999 && abs(top - 0.999) <= 2.0 * (hm[comp].y + CLIP_REACH * min(sqrt(hv[comp].y), hv[comp].y / (2.0 * sqrt(hv[comp].x)))) + 64.0 * E) { pixel_flags = pixel_flags | FLAG_UNCERTAIN; }
769
+ }
770
+ }
771
+ if (cp_chain_run) {
772
+ let t = cp_chain(vec3<f32>(cm[0].x, cm[1].x, cm[2].x), C[0].x, C[1].x, C[2].x, C[3].x, C[4].x, C[5].x, vec3<f32>(cm[0].y, cm[1].y, cm[2].y), vec3<f32>(C[0].y, C[3].y, C[5].y));
773
+ if (t.flag) { pixel_flags = pixel_flags | FLAG_UNCERTAIN; }
774
+ let rows = array<vec3<f32>, 3>(t.a0, t.a1, t.a2);
775
+ for (var comp = 0u; comp < 3u; comp = comp + 1u) {
776
+ hm[comp] = vec2<f32>(t.hm[comp], t.bm[comp]); hv[comp] = vec2<f32>(t.hv[comp], t.bv[comp]);
777
+ for (var c = 0u; c < 3u; c = c + 1u) { an[comp * 3u + c] = vec2<f32>(rows[comp][c], abs(rows[comp][c]) * t.ju); }
778
+ }
779
+ cp_used = true;
780
+ }
781
+ if (cp_used) { for (var k = 0u; k < 9u; k = k + 1u) { cp_a[k] = an[k]; } }
782
+ }
783
+ for (var comp = 0u; comp < 3u; comp = comp + 1u) {
784
+ h_cand[d * 3u + comp] = hm[comp];
785
+ e_mean[comp] = b_add(e_mean[comp], b_scale(hm[comp], share));
786
+ }
787
+
794
788
  for (var c = 0u; c < 3u; c = c + 1u) {
789
+ if (!cp_used) {
795
790
  an[c] = b_mul(b_mul(hs[0], b_rounded(m_of(0u, c))), bs[c]);
796
791
  an[3u + c] = b_mul(b_mul(hs[1], b_rounded(m_of(1u, c))), bs[c]);
797
792
  an[6u + c] = b_mul(b_mul(hs[2], b_rounded(m_of(2u, c))), bs[c]);
793
+ }
798
794
  var bc = b0; if (c == 1u) { bc = b1; } if (c == 2u) { bc = b2; }
799
795
  let wgt = b_mul(b_mul(b_scale(aj, share), b_rounded(bc)), csv[c]);
800
796
  cov[0] = b_add(cov[0], b_mul(b_mul(wgt, an[c]), an[c])); cov[1] = b_add(cov[1], b_mul(b_mul(wgt, an[c]), an[3u + c])); cov[2] = b_add(cov[2], b_mul(b_mul(wgt, an[c]), an[6u + c]));
@@ -835,24 +831,21 @@ let d0 = b_scale(bs[0], aux[eb + 2u] - aux[eb + 5u]);
835
831
  let d1 = b_scale(bs[1], aux[eb + 3u] - aux[eb + 6u]);
836
832
  let d2 = b_scale(bs[2], aux[eb + 4u] - aux[eb + 7u]);
837
833
  let sv = vec2<f32>(sites[o + 1u], sites[o + 4u]);
838
- let a = b_mul(hs[0], b_add(b_add(b_mul(b_rounded(params.m00), d0), b_mul(b_rounded(params.m01), d1)), b_mul(b_rounded(params.m02), d2)));
839
- let b = b_mul(hs[1], b_add(b_add(b_mul(b_rounded(params.m10), d0), b_mul(b_rounded(params.m11), d1)), b_mul(b_rounded(params.m12), d2)));
840
- let c = b_mul(hs[2], b_add(b_add(b_mul(b_rounded(params.m20), d0), b_mul(b_rounded(params.m21), d1)), b_mul(b_rounded(params.m22), d2)));
834
+ var a = b_mul(hs[0], b_add(b_add(b_mul(b_rounded(params.m00), d0), b_mul(b_rounded(params.m01), d1)), b_mul(b_rounded(params.m02), d2)));
835
+ var b = b_mul(hs[1], b_add(b_add(b_mul(b_rounded(params.m10), d0), b_mul(b_rounded(params.m11), d1)), b_mul(b_rounded(params.m12), d2)));
836
+ var c = b_mul(hs[2], b_add(b_add(b_mul(b_rounded(params.m20), d0), b_mul(b_rounded(params.m21), d1)), b_mul(b_rounded(params.m22), d2)));
837
+ if (cp_used) {
838
+
839
+ let e0 = aux[eb + 2u] - aux[eb + 5u]; let e1 = aux[eb + 3u] - aux[eb + 6u]; let e2 = aux[eb + 4u] - aux[eb + 7u];
840
+ a = b_add(b_add(b_scale(cp_a[0], e0), b_scale(cp_a[1], e1)), b_scale(cp_a[2], e2));
841
+ b = b_add(b_add(b_scale(cp_a[3], e0), b_scale(cp_a[4], e1)), b_scale(cp_a[5], e2));
842
+ c = b_add(b_add(b_scale(cp_a[6], e0), b_scale(cp_a[7], e1)), b_scale(cp_a[8], e2));
843
+ }
841
844
  x0 = b_add(x0, b_mul(b_mul(a, a), sv)); x1 = b_add(x1, b_mul(b_mul(b, b), sv)); x2 = b_add(x2, b_mul(b_mul(c, c), sv));
842
845
  }
843
846
  let ajaj = b_mul(aj, aj);
844
847
  res[0] = b_add(res[0], b_mul(ajaj, b_scale(x0, 0.25))); res[1] = b_add(res[1], b_mul(ajaj, b_scale(x1, 0.25))); res[2] = b_add(res[2], b_mul(ajaj, b_scale(x2, 0.25)));
845
848
  }
846
- if (params.correction == 1u) {
847
-
848
- if (abs(pixel_variance.x - params.threshold) <= pixel_variance.y) { pixel_flags = pixel_flags | FLAG_TIE; }
849
- if (pixel_variance.x > params.threshold) {
850
- var corr: array<vec2<f32>, 3>;
851
- flat_correction(cm_average[0], cm_average[1], cm_average[2], &corr);
852
- for (var comp = 0u; comp < 3u; comp = comp + 1u) { s[comp] = b_add(s[comp], b_mul(aj, corr[comp])); }
853
- pixel_flags = pixel_flags | FLAG_CORRECTED;
854
- }
855
- }
856
849
  }
857
850
  }
858
851
 
@@ -869,6 +862,11 @@ flags[3u * i + 1u] = mask0;
869
862
  flags[3u * i + 2u] = mask1;
870
863
  }
871
864
  `;
865
+ /** The pixel pass (`DISPLAY_VIEW_QUALITY_PIXELS_BODY_WGSL`) with the coupled steps' text: the stub by default, the coupled steps on demand (#593). */
866
+ export function assembleDisplayViewQualityPixelsWgsl(coupledWgsl = DISPLAY_VIEW_COUPLED_STUB_WGSL) {
867
+ return DISPLAY_VIEW_QUALITY_PIXELS_BODY_WGSL + "\n" + coupledWgsl;
868
+ }
869
+ export const DISPLAY_VIEW_QUALITY_PIXELS_WGSL = /* @__PURE__ */ assembleDisplayViewQualityPixelsWgsl();
872
870
  /** The lattice pass with a material module appended (`fn material_at(p: vec2<f32>) -> u32`, `var<private> material_uncertain: bool`). */
873
871
  export function assembleDisplayViewQualityLatticeWgsl(materialModuleWgsl) {
874
872
  return DISPLAY_VIEW_QUALITY_LATTICE_WGSL + "\n" + materialModuleWgsl + "\n";