@photivra/engine 2.21.0 → 2.23.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 (172) hide show
  1. package/CHANGELOG.md +150 -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 +76 -0
  30. package/dist/color/neighbor-highlight-reconstruction.js +257 -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 +102 -0
  58. package/dist/facade/display-view-rendering.js +633 -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 +55 -240
  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 +62 -19
  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 +13 -0
  115. package/dist/gpu/wgsl-display-view-coupled-stub.js +29 -0
  116. package/dist/gpu/wgsl-display-view-coupled-stub.js.map +1 -0
  117. package/dist/gpu/wgsl-display-view-coupled.d.ts +91 -0
  118. package/dist/gpu/wgsl-display-view-coupled.js +365 -0
  119. package/dist/gpu/wgsl-display-view-coupled.js.map +1 -0
  120. package/dist/gpu/wgsl-display-view-neighbors.d.ts +46 -0
  121. package/dist/gpu/wgsl-display-view-neighbors.js +114 -0
  122. package/dist/gpu/wgsl-display-view-neighbors.js.map +1 -0
  123. package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +6 -9
  124. package/dist/gpu/wgsl-display-view-quality-kernel.js +113 -113
  125. package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
  126. package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +1 -41
  127. package/dist/gpu/wgsl-display-view-speed-kernel.js +73 -10
  128. package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
  129. package/dist/index.d.ts +11 -3
  130. package/dist/index.js +9 -1
  131. package/dist/index.js.map +1 -1
  132. package/dist/output/camera-channel-response.d.ts +50 -0
  133. package/dist/output/camera-channel-response.js +69 -0
  134. package/dist/output/camera-channel-response.js.map +1 -0
  135. package/dist/output/native-capture-sdr.js +5 -2
  136. package/dist/output/native-capture-sdr.js.map +1 -1
  137. package/dist/output/sdr-rendering.d.ts +18 -1
  138. package/dist/output/sdr-rendering.js +39 -2
  139. package/dist/output/sdr-rendering.js.map +1 -1
  140. package/dist/sensor/native-sensor-report.d.ts +10 -0
  141. package/dist/sensor/native-sensor-report.js +16 -0
  142. package/dist/sensor/native-sensor-report.js.map +1 -0
  143. package/dist/sensor/sensor-characteristics.d.ts +81 -13
  144. package/dist/sensor/sensor-characteristics.js +10 -6
  145. package/dist/sensor/sensor-characteristics.js.map +1 -1
  146. package/docs/API_REFERENCE.md +117 -4
  147. package/docs/QUICK_START.md +37 -8
  148. package/docs/USAGE.md +105 -22
  149. package/docs/api/capture-c2pa-embed.md +177 -0
  150. package/docs/api/capture-dng-import.md +86 -10
  151. package/docs/api/capture-dng-opcodes.md +93 -0
  152. package/docs/api/capture-dng-profile-maps.md +141 -0
  153. package/docs/api/capture-dng-stage-image.md +43 -0
  154. package/docs/api/capture-jpeg-xl-tiles.md +33 -0
  155. package/docs/api/capture-lossy-jpeg.md +41 -0
  156. package/docs/api/capture-native-raw-development.md +2 -1
  157. package/docs/api/core-execution-error.md +43 -0
  158. package/docs/api/core-version.md +1 -1
  159. package/docs/api/exports.json +255 -5
  160. package/docs/api/facade-display-view-gpu.md +5 -2
  161. package/docs/api/facade-display-view.md +11 -15
  162. package/docs/api/facade-fast-methods.md +38 -9
  163. package/docs/api/facade-quality-paths.md +24 -0
  164. package/docs/api/facade-scene-radiance.md +1 -1
  165. package/docs/api/facade-simulate-capture.md +24 -7
  166. package/docs/api/facade-simulate-display-view.md +10 -12
  167. package/docs/api/gpu-image-kernel-execution.md +0 -36
  168. package/docs/api/output-camera-channel-response.md +55 -0
  169. package/docs/api/output-sdr-rendering.md +6 -1
  170. package/docs/api/sensor-sensor-characteristics.md +54 -2
  171. package/llms.txt +1 -0
  172. package/package.json +6 -5
@@ -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
@@ -106,8 +99,10 @@ export const DISPLAY_VIEW_QUALITY_FLAG = /* @__PURE__ */ Object.freeze({
106
99
  ahdChoice: 32,
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,
102
+ /** #605: a chain needed neighbor ratios the host had not given (redone with them; the host sets bit 0 if any is left). */
103
+ neighborRatios: 128,
109
104
  /** The bits that require the host's recomputation. */
110
- recompute: 47
105
+ recompute: 35
111
106
  });
112
107
  /** #533: flag words per display pixel: the flags, then the 36-bit mask of saturated real pixels. */
113
108
  export const DISPLAY_VIEW_QUALITY_FLAG_WORDS = 3;
@@ -117,8 +112,6 @@ export const DISPLAY_VIEW_QUALITY_FLAG_WORDS = 3;
117
112
  * 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
113
  */
119
114
  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
115
  /**
123
116
  * A site whose uncertain lattice points (the material module's flag) could move its electrons by more than this fraction of
124
117
  * their value is flagged for host recomputation; a smaller uncertainty enters the site's bound instead (the tap weights times
@@ -156,11 +149,11 @@ count: u32, row0: u32, region_w: u32, region_x: u32,
156
149
  region_y: u32, margin: u32, native_w: u32, native_h: u32,
157
150
  columns: u32, tone: u32, reach: u32, candidates: u32,
158
151
  site_x0: i32, site_y0: i32, site_w: u32, site_h: u32,
159
- correction: u32, state_count: u32, taps: u32, groups: u32,
152
+ unused_16: u32, unused_17: u32, taps: u32, groups: u32,
160
153
  lattice_total: u32, gain_at_clip0: u32, gain_at_clip1: u32, gain_at_clip2: u32,
161
154
  k0: f32, k1: f32, k2: f32, reach2: f32,
162
155
  dark0: f32, dark1: f32, dark2: f32, clip_level: f32,
163
- c0_0: f32, c0_1: f32, c0_2: f32, threshold: f32,
156
+ c0_0: f32, c0_1: f32, c0_2: f32, unused_35: f32,
164
157
  g0: f32, g1: f32, g2: f32, scale_u: f32,
165
158
  m00: f32, m01: f32, m02: f32, m10: f32,
166
159
  m11: f32, m12: f32, m20: f32, m21: f32,
@@ -531,30 +524,26 @@ write_site(i, c, e, de, flag);
531
524
  }
532
525
  `;
533
526
  /** 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;
527
+ /*
528
+ * 2.22.0: in the luminance branch the nested loops read the colour matrix rows from one local array (`mm`) instead of calling
529
+ * `m_of` (a `switch`): SwiftShader's compiler ended the GPU process on the `switch` inside those loops (after about 44 s). The
530
+ * values are the same (docs/WEBGPU.md, "Coupled rendering steps").
531
+ */
532
+ export const DISPLAY_VIEW_QUALITY_PIXELS_BODY_WGSL = /* wgsl */ `${DISPLAY_VIEW_QUALITY_COMMON_WGSL}
540
533
  const CAND_BASE: u32 = ${DISPLAY_VIEW_QUALITY_AUX.candidates}u;
541
534
  const CAND_STRIDE: u32 = ${CANDIDATE_PHASE_STRIDE}u;
542
535
  const FLAG_UNCERTAIN: u32 = ${DISPLAY_VIEW_QUALITY_FLAG.materialUncertain}u;
543
536
  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
537
  const FLAG_CHOICE: u32 = ${DISPLAY_VIEW_QUALITY_FLAG.ahdChoice}u;
548
538
  const FLAG_HIGHLIGHT: u32 = ${DISPLAY_VIEW_QUALITY_FLAG.highlightUndecided}u;
549
539
  const CHOICE_SIGMA: f32 = ${literal(DISPLAY_VIEW_QUALITY_CHOICE_SIGMA)};
550
540
  @group(0) @binding(1) var<storage, read> aux: array<f32>;
551
541
  @group(0) @binding(2) var<storage, read> geometry: array<f32>;
552
542
  @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>;
543
+ @group(0) @binding(4) var<storage, read_write> out: array<f32>;
544
+ @group(0) @binding(5) var<storage, read_write> flags: array<u32>;
545
+
546
+ fn cp_k(i: u32) -> f32 { return aux[${DISPLAY_VIEW_QUALITY_AUX.size}u + i]; }
558
547
 
559
548
  var<private> pixel_flags: u32;
560
549
  ${REINHARD_WGSL}
@@ -571,70 +560,10 @@ return o;
571
560
  }
572
561
 
573
562
  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
563
  @compute @workgroup_size(${DISPLAY_VIEW_QUALITY_WORKGROUP_SIZE})
635
564
  fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) wg: vec3<u32>) {
636
565
  let i = gid.x + gid.y * wg.x * ${DISPLAY_VIEW_QUALITY_WORKGROUP_SIZE}u;
637
- if (i >= params.count) { return; }
566
+ if (i >= params.count || nb_skip(i)) { return; }
638
567
  pixel_flags = 0u;
639
568
  let rx = i % params.region_w;
640
569
  let ry = params.row0 + i / params.region_w;
@@ -647,6 +576,9 @@ let ny = bitcast<u32>(geometry[row + 1u]);
647
576
  let margin = i32(params.margin);
648
577
  let reinhard = params.tone == 1u;
649
578
  let count = params.candidates;
579
+
580
+ var cp_used = false;
581
+ var cp_a: array<vec2<f32>, 9>;
650
582
  let share = select(1.0, 0.5, count == 2u);
651
583
 
652
584
  let xb_even = geometry[col + 8u]; let xb_odd = geometry[col + 9u];
@@ -711,8 +643,6 @@ let bit = j * nx + ii;
711
643
  if (bit < 32u) { mask0 = mask0 | (1u << bit); } else { mask1 = mask1 | (1u << (bit - 32u)); }
712
644
  } else if ((clip_any & 2u) != 0u) { undecided = true; }
713
645
  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
646
  var bs: array<vec2<f32>, 3>; var hs: array<vec2<f32>, 3>;
717
647
  var hv: array<vec2<f32>, 3>;
718
648
 
@@ -739,17 +669,26 @@ cm[0] = b_add(cm[0], b_scale(sm, w0)); cm[1] = b_add(cm[1], b_scale(sm, w1)); cm
739
669
  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
670
  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
671
  }
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)); }
672
+ for (var c = 0u; c < 3u; c = c + 1u) { if (exact[c]) { cm[c].y = 0.0; } }
673
+
674
+
675
+ var cp_chain_run = false;
676
+ if (cp_on() && cp_reconstruct()) {
677
+ 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));
678
+ if (reach == 2u) { pixel_flags = pixel_flags | FLAG_UNCERTAIN; }
679
+ cp_chain_run = reach >= 1u;
680
+ }
681
+ let cp_unclipped = cp_on() && cp_reconstruct();
743
682
 
744
683
 
745
684
  var bm: array<vec2<f32>, 3>; var bv: array<vec2<f32>, 3>;
746
685
  for (var c = 0u; c < 3u; c = c + 1u) {
747
686
  let gc = b_rounded(g_of(c));
748
687
  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); }
688
+ if (exact[c] && cm[c].x == 1.0 && gain_at_clip(c) && !cp_unclipped) { um = vec2<f32>(params.clip_level, 0.0); }
750
689
  let uv = b_mul(b_mul(gc, gc), C[select(select(0u, 3u, c == 1u), 5u, c == 2u)]);
751
690
  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; }
691
+ if (cp_unclipped || (gap > 0.0 && gap * gap > params.reach2 * uv.x)) { bm[c] = um; bv[c] = uv; bs[c] = gc; }
753
692
  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
693
  }
755
694
 
@@ -785,16 +724,75 @@ if (variance.x > 0.0) { skew = b_div(third, b_mul(variance, b_sqrt(variance)));
785
724
  moments = unit_clip(mean, variance, skew);
786
725
  }
787
726
  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
727
  }
792
728
 
793
729
  var an: array<vec2<f32>, 9>;
730
+ cp_used = false;
731
+ if (cp_on()) {
732
+ if (!cp_chain_run && cp_luminance()) {
733
+ var mu = vec3<f32>(0.0); var dmu = vec3<f32>(0.0); var dsv = vec3<f32>(0.0);
734
+ var srow = array<vec3<f32>, 3>(vec3<f32>(0.0), vec3<f32>(0.0), vec3<f32>(0.0));
735
+ 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);
736
+ 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));
737
+ for (var r = 0u; r < 3u; r = r + 1u) {
738
+ mu[r] = mm[r][0] * bm[0].x + mm[r][1] * bm[1].x + mm[r][2] * bm[2].x;
739
+ dmu[r] = abs(mm[r][0]) * bm[0].y + abs(mm[r][1]) * bm[1].y + abs(mm[r][2]) * bm[2].y;
740
+ 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;
741
+ for (var q = 0u; q < 3u; q = q + 1u) {
742
+ var v = 0.0;
743
+ for (var a = 0u; a < 3u; a = a + 1u) { for (var b = 0u; b < 3u; b = b + 1u) {
744
+ var bab = bv[a].x; if (a != b) { bab = bs[a].x * bs[b].x * cc[a * 3u + b]; }
745
+ v = v + mm[r][a] * mm[q][b] * bab;
746
+ } }
747
+ srow[r][q] = v;
748
+ }
749
+ }
750
+ let t = cp_tone(mu, srow[0], srow[1], srow[2], dmu, dsv);
751
+ if (t.flag) { pixel_flags = pixel_flags | FLAG_UNCERTAIN; }
752
+ if (cp_desaturate() && t.top) { cp_chain_run = true; }
753
+ else {
754
+ let rows = array<vec3<f32>, 3>(t.a0, t.a1, t.a2);
755
+ for (var comp = 0u; comp < 3u; comp = comp + 1u) {
756
+ hm[comp] = vec2<f32>(t.hm[comp], t.bm[comp]); hv[comp] = vec2<f32>(t.hv[comp], t.bv[comp]);
757
+ for (var c = 0u; c < 3u; c = c + 1u) {
758
+ let jmc = rows[comp].x * m_of(0u, c) + rows[comp].y * m_of(1u, c) + rows[comp].z * m_of(2u, c);
759
+ 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));
760
+ let value = jmc * bs[c].x;
761
+ an[comp * 3u + c] = vec2<f32>(value, ajm * bs[c].y + abs(value) * (t.ju + 4.0 * E));
762
+ }
763
+ }
764
+ cp_used = true;
765
+ }
766
+ } else if (!cp_chain_run && cp_desaturate() && !reinhard) {
767
+ for (var comp = 0u; comp < 3u; comp = comp + 1u) {
768
+ let top = hm[comp].x + CLIP_REACH * sqrt(hv[comp].x);
769
+ if (hm[comp].x > 0.0 && top >= 0.999) { cp_chain_run = true; }
770
+ 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; }
771
+ }
772
+ }
773
+ if (cp_chain_run && nb_ratio(i, j * nx + ii)) {
774
+ 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));
775
+ if (t.flag) { pixel_flags = pixel_flags | FLAG_UNCERTAIN; }
776
+ let rows = array<vec3<f32>, 3>(t.a0, t.a1, t.a2);
777
+ for (var comp = 0u; comp < 3u; comp = comp + 1u) {
778
+ hm[comp] = vec2<f32>(t.hm[comp], t.bm[comp]); hv[comp] = vec2<f32>(t.hv[comp], t.bv[comp]);
779
+ for (var c = 0u; c < 3u; c = c + 1u) { an[comp * 3u + c] = vec2<f32>(rows[comp][c], abs(rows[comp][c]) * t.ju); }
780
+ }
781
+ cp_used = true;
782
+ }
783
+ if (cp_used) { for (var k = 0u; k < 9u; k = k + 1u) { cp_a[k] = an[k]; } }
784
+ }
785
+ for (var comp = 0u; comp < 3u; comp = comp + 1u) {
786
+ h_cand[d * 3u + comp] = hm[comp];
787
+ e_mean[comp] = b_add(e_mean[comp], b_scale(hm[comp], share));
788
+ }
789
+
794
790
  for (var c = 0u; c < 3u; c = c + 1u) {
791
+ if (!cp_used) {
795
792
  an[c] = b_mul(b_mul(hs[0], b_rounded(m_of(0u, c))), bs[c]);
796
793
  an[3u + c] = b_mul(b_mul(hs[1], b_rounded(m_of(1u, c))), bs[c]);
797
794
  an[6u + c] = b_mul(b_mul(hs[2], b_rounded(m_of(2u, c))), bs[c]);
795
+ }
798
796
  var bc = b0; if (c == 1u) { bc = b1; } if (c == 2u) { bc = b2; }
799
797
  let wgt = b_mul(b_mul(b_scale(aj, share), b_rounded(bc)), csv[c]);
800
798
  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 +833,21 @@ let d0 = b_scale(bs[0], aux[eb + 2u] - aux[eb + 5u]);
835
833
  let d1 = b_scale(bs[1], aux[eb + 3u] - aux[eb + 6u]);
836
834
  let d2 = b_scale(bs[2], aux[eb + 4u] - aux[eb + 7u]);
837
835
  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)));
836
+ 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)));
837
+ 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)));
838
+ 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)));
839
+ if (cp_used) {
840
+
841
+ let e0 = aux[eb + 2u] - aux[eb + 5u]; let e1 = aux[eb + 3u] - aux[eb + 6u]; let e2 = aux[eb + 4u] - aux[eb + 7u];
842
+ a = b_add(b_add(b_scale(cp_a[0], e0), b_scale(cp_a[1], e1)), b_scale(cp_a[2], e2));
843
+ b = b_add(b_add(b_scale(cp_a[3], e0), b_scale(cp_a[4], e1)), b_scale(cp_a[5], e2));
844
+ c = b_add(b_add(b_scale(cp_a[6], e0), b_scale(cp_a[7], e1)), b_scale(cp_a[8], e2));
845
+ }
841
846
  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
847
  }
843
848
  let ajaj = b_mul(aj, aj);
844
849
  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
850
  }
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
851
  }
857
852
  }
858
853
 
@@ -864,11 +859,16 @@ out[o + 3u] = cov[0].x + res[0].x; out[o + 4u] = cov[3].x + res[1].x; out[o + 5u
864
859
  out[o + 6u] = cov[1].x; out[o + 7u] = cov[2].x; out[o + 8u] = cov[4].x;
865
860
  out[o + 9u] = max(s[0].y, max(s[1].y, s[2].y));
866
861
  out[o + 10u] = max(max(cov[0].y + res[0].y, cov[3].y + res[1].y), max(cov[5].y + res[2].y, max(cov[1].y, max(cov[2].y, cov[4].y))));
867
- flags[3u * i] = pixel_flags | select(0u, FLAG_HIGHLIGHT, undecided);
862
+ flags[3u * i] = pixel_flags | select(0u, FLAG_HIGHLIGHT, undecided) | nb_flag();
868
863
  flags[3u * i + 1u] = mask0;
869
864
  flags[3u * i + 2u] = mask1;
870
865
  }
871
866
  `;
867
+ /** The pixel pass (`DISPLAY_VIEW_QUALITY_PIXELS_BODY_WGSL`) with the coupled steps' text: the stub by default, the coupled steps on demand (#593). */
868
+ export function assembleDisplayViewQualityPixelsWgsl(coupledWgsl = DISPLAY_VIEW_COUPLED_STUB_WGSL) {
869
+ return DISPLAY_VIEW_QUALITY_PIXELS_BODY_WGSL + "\n" + coupledWgsl;
870
+ }
871
+ export const DISPLAY_VIEW_QUALITY_PIXELS_WGSL = /* @__PURE__ */ assembleDisplayViewQualityPixelsWgsl();
872
872
  /** The lattice pass with a material module appended (`fn material_at(p: vec2<f32>) -> u32`, `var<private> material_uncertain: bool`). */
873
873
  export function assembleDisplayViewQualityLatticeWgsl(materialModuleWgsl) {
874
874
  return DISPLAY_VIEW_QUALITY_LATTICE_WGSL + "\n" + materialModuleWgsl + "\n";