@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wgsl-display-view-coupled.js","sourceRoot":"","sources":["../../src/gpu/wgsl-display-view-coupled.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * #593, #601 (2.22.0): the display view's coupled rendering steps on the GPU, shared by the Speed kernel and the Quality pixel\n * pass: the luminance tone curves by conditioning on luminance (`cp_tone`), and `highlightMode: \"reconstruct\"` and the\n * desaturation by the 3-D Gauss–Hermite rule over the development chain (`cp_chain`), the float32 forms of\n * src/facade/display-view-rendering.ts with the request's fast or full rule. On demand: a kernel takes this text only for a view\n * that asks for the coupled steps (its pipeline label ends in `+coupled`); every other view takes `DISPLAY_VIEW_COUPLED_STUB_WGSL`.\n *\n * Constants come from the kernel's aux table after its own entries (`cp_k(i)`, which each kernel defines), laid out as\n * `DISPLAY_VIEW_COUPLED` (the host's `displayViewCoupledConstants`). The kernels define `phi` and `pq` (Abramowitz–Stegun) and\n * `CLIP_REACH`; nothing else is shared.\n *\n * Error bounds (first order, float32, E = 2^-23; docs/WEBGPU.md, \"Coupled rendering steps\"). Every function returns, besides\n * its moments, absolute bounds of the mean and the variance against the float64 reference and the slopes' relative bound:\n * - tone: per node the clipped-normal terms (`CLIP_MEAN_U`·r·σ, `CLIP_VARIANCE_U`·r²·σ²), the conditional variance's\n * cancellation (0.8·r·√(32·E·Σ_kk)), the node position through the slope and the ratio's relative error (log2 and exp2 per the\n * WGSL accuracy table, the image-kernel accelerator's tone analysis); then one E per node of the sums;\n * - chain: per node the rounding of the developed pixel (white balance and blend 8E of the largest channel, matrix 3E per term,\n * tone ratio η, desaturation 8E) carried to the output through the node's own slopes, plus the node point's rounding through\n * the slopes; then one E per node of the sums. The chain is continuous (clip, blend, maximum and desaturation all are), so a\n * branch taken differently on either side of a kink moves the output by at most the slope times the input's error;\n * - inputs: the caller's bounds of the means through |slopes|, of the variances through 0.8·|slopes|·√δ.\n * A decision the reference takes on a threshold (the blend's reach, a component reaching 1 with the desaturation, the fast\n * rule's range, a node at L = 0 where the ratio jumps) that the float32 values cannot settle sets the pixel's recompute flag:\n * the host renders that display pixel with the reference.\n */\n\n/** Layout of the coupled-constants buffer (float32 words). */\nexport const DISPLAY_VIEW_COUPLED = /* @__PURE__ */ Object.freeze({\n on: 0, luminance: 1, tone: 2, a: 3, n: 4, inverseWhite: 5, ratioAtZero: 6, weights: 7, reconstruct: 10, desaturate: 11, fast: 12,\n gains: 13, clipLevel: 16, matrix: 17, chainPoints: 26, chainX: 27, chainW: 43, hermiteX: 59, hermiteW: 67, legendreX: 75, legendreW: 91, size: 107\n});\n/** The largest finite float32 stands for r(0+) = ∞ (Naka–Rushton below exponent 1). */\nexport const DISPLAY_VIEW_COUPLED_INFINITE_RATIO = 3.4028234663852886e38;\n\nimport { DISPLAY_VIEW_COUPLED_DECLARATIONS_WGSL } from \"./wgsl-display-view-coupled-stub.js\";\n// #605: the neighbor reconstruction's GPU code loads with the coupled steps (one on-demand chunk).\nimport { displayViewNeighborsWgsl } from \"./wgsl-display-view-neighbors.js\";\nexport { dispatchWithNeighborRatios } from \"./wgsl-display-view-neighbors.js\";\n\nconst E_LITERAL = \"1.1920928955078125e-7\";\nconst C = DISPLAY_VIEW_COUPLED;\n\n/** The coupled steps (see the module comment). */\nexport const DISPLAY_VIEW_COUPLED_WGSL = /* wgsl */ `${DISPLAY_VIEW_COUPLED_DECLARATIONS_WGSL}\nconst CP_E: f32 = ${E_LITERAL};\nconst CP_CLIP_MEAN_U: f32 = 1400.0;\nconst CP_CLIP_VARIANCE_U: f32 = 36000.0;\nconst CP_START: f32 = 0.8;\nfn cp_luminance() -> bool { return cp_k(${C.luminance}u) != 0.0; }\nfn cp_reconstruct() -> bool { return cp_k(${C.reconstruct}u) != 0.0; }\nfn cp_desaturate() -> bool { return cp_k(${C.desaturate}u) != 0.0; }\nfn cp_w() -> vec3<f32> { return vec3<f32>(cp_k(${C.weights}u), cp_k(${C.weights + 1}u), cp_k(${C.weights + 2}u)); }\nfn cp_m(r: u32) -> vec3<f32> { return vec3<f32>(cp_k(${C.matrix}u + 3u * r), cp_k(${C.matrix + 1}u + 3u * r), cp_k(${C.matrix + 2}u + 3u * r)); }\nfn cp_dot(a: vec3<f32>, b: vec3<f32>) -> f32 { return (a.x * b.x + a.y * b.y) + a.z * b.z; }\nfn cp_unit(k: u32) -> vec3<f32> { return vec3<f32>(select(0.0, 1.0, k == 0u), select(0.0, 1.0, k == 1u), select(0.0, 1.0, k == 2u)); }\n// The tone ratio r(L) = f(L)/L, its slope r′ and its relative bound η in units of E (L > 0).\nfn cp_ratio(l: f32) -> vec3<f32> {\n let a = cp_k(${C.a}u);\n if (cp_k(${C.tone}u) == 2.0) { let d = 1.0 + l; return vec3<f32>((1.0 + l * a) / d, (a - 1.0) / (d * d), 16.0); }\n let n = cp_k(${C.n}u);\n let iw = cp_k(${C.inverseWhite}u);\n let lg = log2(a / l);\n let z = n * lg;\n var g = 0.0; var ug = 0.0;\n if (z >= 0.0) { let p = exp2(-z); g = p / (1.0 + p); ug = 1.0 / (1.0 + p); }\n else { let u = exp2(z); g = 1.0 / (1.0 + u); ug = u / (1.0 + u); }\n let dz = n * (8.5 + 3.0 * abs(lg)) + abs(z);\n return vec3<f32>(g * iw / l, g * (n * ug - 1.0) * iw / (l * l), 2.0 * (0.7 * dz + 3.0 + 2.0 * abs(z)) + 24.0);\n}\n// clip(Z, 0, 1) for Z ~ N(m, v), standardized (cancellation-free): (mean, variance, P(0 < Z < 1), P(Z ≥ 1)).\nfn cp_clip(m: f32, v: f32) -> vec4<f32> {\n if (!(v > 0.0)) { let inside = m > 0.0 && m < 1.0; return vec4<f32>(clamp(m, 0.0, 1.0), 0.0, select(0.0, 1.0, inside), select(0.0, 1.0, m >= 1.0)); }\n let s = sqrt(v);\n let a = -m / s;\n let b = (1.0 - m) / s;\n var pa = 0.0; var da = 0.0;\n if (a > CLIP_REACH) { pa = 1.0; } else 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) { pb = 0.0; qb = 1.0; } else if (!(b > CLIP_REACH)) { let p = pq(b); pb = p.x; qb = p.y; db = phi(b); }\n let inside = pb - pa;\n let eg = a * pa + (da - db) + b * qb;\n let eg2 = a * a * pa + inside - (b * db - a * da) + b * b * qb;\n return vec4<f32>(m + s * eg, max(0.0, v * (eg2 - eg * eg)), inside, qb);\n}\n// Whether the reconstruct blend is within reach of channels with means cm and variances cv: 0 no, 1 yes, 2 undecided in float32.\nfn cp_reconstruct_reach(cm: vec3<f32>, cv: vec3<f32>) -> u32 {\n var state = 0u;\n for (var k = 0u; k < 3u; k = k + 1u) {\n let top = cm[k] + CLIP_REACH * sqrt(max(0.0, cv[k]));\n let margin = 16.0 * CP_E * (abs(cm[k]) + abs(top));\n let start = select(CP_START, NB_H, nb_on());\n if (!(top < start - margin)) { if (top >= start + margin) { return 1u; } state = 2u; }\n }\n return state;\n}\nfn cp_tone(mu: vec3<f32>, s0: vec3<f32>, s1: vec3<f32>, s2: vec3<f32>, dmu: vec3<f32>, dsv: vec3<f32>) -> CpOut {\n let w = cp_w();\n let mul = cp_dot(w, mu);\n let sw = vec3<f32>(cp_dot(s0, w), cp_dot(s1, w), cp_dot(s2, w));\n let vl = cp_dot(w, sw);\n let sl = select(0.0, sqrt(vl), vl > 0.0);\n var beta = vec3<f32>(0.0);\n if (sl > 0.0) { beta = sw / vl; }\n let skk = vec3<f32>(s0.x, s1.y, s2.z);\n let cv = max(vec3<f32>(0.0), skk - beta * sw);\n var centre = clamp(mu, vec3<f32>(0.0), vec3<f32>(1.0));\n if (mul > 0.0) { centre = clamp(mu * cp_ratio(mul).x, vec3<f32>(0.0), vec3<f32>(1.0)); }\n var t: CpOut;\n var second = vec3<f32>(0.0);\n var j = array<vec3<f32>, 3>(vec3<f32>(0.0), vec3<f32>(0.0), vec3<f32>(0.0));\n let dl = 8.0 * CP_E * (abs(mul) + 9.0 * sl);\n let hi = mul + CLIP_REACH * sl;\n let ratio_margin = 64.0 * CP_E * (abs(mul) + sl);\n // The fast rule's range test and the split at L = 0, as the reference takes them (undecided: recompute).\n let fast_test = mul - 2.0 * CLIP_REACH * sl;\n let fast = cp_k(${C.fast}u) != 0.0 && (fast_test > 0.0 || hi < 0.0);\n if (cp_k(${C.fast}u) != 0.0 && sl > 0.0 && abs(fast_test) <= ratio_margin) { t.flag = true; }\n let split = mul - CLIP_REACH * sl < 0.0 && hi > 0.0;\n if (sl > 0.0 && (abs(mul - CLIP_REACH * sl) <= ratio_margin || abs(hi) <= ratio_margin)) { t.flag = true; }\n var pieces = 1u; var nodes = 1u;\n if (sl > 0.0) { if (fast) { nodes = 8u; } else { nodes = 64u; if (split) { pieces = 2u; } } }\n var count = 0.0;\n for (var piece = 0u; piece < pieces; piece = piece + 1u) {\n var za = -CLIP_REACH; var zb = CLIP_REACH;\n if (pieces == 2u) { if (piece == 0u) { zb = -mul / sl; } else { za = -mul / sl; } }\n for (var i = 0u; i < nodes; i = i + 1u) {\n var l = mul; var weight = 1.0;\n if (nodes == 8u) { l = mul + sl * cp_k(${C.hermiteX}u + i); weight = cp_k(${C.hermiteW}u + i); }\n else if (nodes == 64u) {\n let width = (zb - za) / 4.0;\n let hw = width / 2.0;\n let z = za + (f32(i / 16u) + 0.5) * width + hw * cp_k(${C.legendreX}u + (i % 16u));\n l = mul + sl * z;\n weight = hw * cp_k(${C.legendreW}u + (i % 16u)) * phi(z);\n }\n count = count + 1.0;\n var r = 1.0; var rp = 0.0; var eta = 0.0;\n if (l > 0.0) { let q = cp_ratio(l); r = q.x; rp = q.y; eta = q.z; }\n t.ju = max(t.ju, eta);\n for (var k = 0u; k < 3u; k = k + 1u) {\n let m = mu[k] + beta[k] * (l - mul);\n let c = cp_clip(r * m, r * r * cv[k]);\n let d = c.x - centre[k];\n t.hm[k] = t.hm[k] + weight * c.x;\n second[k] = second[k] + weight * (c.y + d * d);\n // The reference's test of a component reaching 1 (b ≤ 8.5 standard deviations); undecided in float32: recompute.\n let zv = r * r * cv[k];\n if (zv > 0.0) {\n let b = (1.0 - r * m) / sqrt(zv);\n if (!(b > CLIP_REACH)) { t.top = true; }\n if (abs(b - CLIP_REACH) <= 64.0 * CP_E * (CLIP_REACH + abs(r * m) / sqrt(zv))) { t.flag = true; }\n } else if (r * m >= 1.0) { t.top = true; }\n let e1 = c.x - c.w;\n j[k] = j[k] + weight * (cp_unit(k) * (r * c.z) + select(vec3<f32>(0.0), w * (rp * e1 / r), rp != 0.0));\n let err = CP_CLIP_MEAN_U * CP_E * r * sqrt(cv[k]) + 0.8 * r * sqrt(32.0 * CP_E * skk[k]) + c.z * (abs(rp * m) + r * abs(beta[k])) * dl + abs(c.x) * eta * CP_E;\n t.bm[k] = t.bm[k] + weight * err;\n t.bv[k] = t.bv[k] + weight * (2.0 * err + CP_CLIP_VARIANCE_U * CP_E * r * r * cv[k]);\n }\n }\n }\n let r0 = cp_k(${C.ratioAtZero}u);\n if (sl > 0.0 && r0 != 1.0 && abs(mul) < CLIP_REACH * sl) {\n let density = phi(mul / sl) / sl;\n for (var k = 0u; k < 3u; k = k + 1u) {\n let m = mu[k] - beta[k] * mul;\n let below = cp_clip(m, cv[k]).x;\n var above = 0.0;\n if (r0 > 1e30) { if (cv[k] > 0.0) { above = pq(m / sqrt(cv[k])).x; } else { above = select(0.0, 1.0, m > 0.0); } }\n else { above = cp_clip(r0 * m, r0 * r0 * cv[k]).x; }\n j[k] = j[k] + w * (density * (above - below));\n }\n }\n let shifted = t.hm - centre;\n t.hv = max(vec3<f32>(0.0), second - shifted * shifted);\n t.a0 = j[0]; t.a1 = j[1]; t.a2 = j[2];\n for (var k = 0u; k < 3u; k = k + 1u) {\n let ak = abs(j[k]);\n t.bm[k] = t.bm[k] + count * CP_E * abs(t.hm[k]) + cp_dot(ak, dmu) + 0.8 * cp_dot(ak, sqrt(dsv));\n t.bv[k] = t.bv[k] + count * CP_E * second[k] + 2.0 * abs(shifted[k]) * t.bm[k] + cp_dot(ak * ak, dsv);\n }\n t.ju = (t.ju + 4.0 * count) * CP_E;\n return t;\n}\n// One node of the development chain at camera channels c: the rendered pixel, the slopes ∂out/∂c (rows), the rounding bound\n// per component (before the node point's own rounding) and whether a luminance at 0 makes the ratio's jump undecided.\nstruct CpNode { out: vec3<f32>, t0: vec3<f32>, t1: vec3<f32>, t2: vec3<f32>, err: vec3<f32>, flag: bool };\nfn cp_develop(c: vec3<f32>) -> CpNode {\n let g = vec3<f32>(cp_k(${C.gains}u), cp_k(${C.gains + 1}u), cp_k(${C.gains + 2}u));\n let lc = cp_k(${C.clipLevel}u);\n let u = c * g;\n var b = u;\n var jb = array<vec3<f32>, 3>(vec3<f32>(g.x, 0.0, 0.0), vec3<f32>(0.0, g.y, 0.0), vec3<f32>(0.0, 0.0, g.z));\n var node: CpNode;\n // #605: the neighbor rebuild (wgsl-display-view-neighbors.ts) with its own rounding bound.\n var eb = 8.0 * CP_E * max(abs(u.x), max(abs(u.y), abs(u.z)));\n if (nb_on()) {\n let nb = nb_rebuild(c, g);\n b = nb.b; jb = array<vec3<f32>, 3>(nb.j0, nb.j1, nb.j2); eb = nb.err;\n } else if (!cp_reconstruct()) {\n for (var k = 0u; k < 3u; k = k + 1u) { if (u[k] > lc) { b[k] = lc; jb[k][k] = 0.0; } }\n } else {\n let s = select(select(c.z, c.y, c.y > c.z), select(c.z, c.x, c.x > c.z), c.x > c.y);\n if (s > CP_START) {\n let si = select(select(2u, 1u, c.y > c.z), select(2u, 0u, c.x > c.z), c.x > c.y);\n let kk = min(u, vec3<f32>(lc));\n let n = select(select(kk.z, kk.y, kk.y > kk.z), select(kk.z, kk.x, kk.x > kk.z), kk.x > kk.y);\n let ni = select(select(2u, 1u, kk.y > kk.z), select(2u, 0u, kk.x > kk.z), kk.x > kk.y);\n let ns = select(g[ni], 0.0, u[ni] > lc);\n let t = select((s - CP_START) / (1.0 - CP_START), 1.0, s >= 1.0);\n let ts = select(1.0 / (1.0 - CP_START), 0.0, s >= 1.0);\n b = (1.0 - t) * u + t * n;\n for (var k = 0u; k < 3u; k = k + 1u) {\n var row = cp_unit(k) * ((1.0 - t) * g[k]);\n row = row + cp_unit(ni) * (t * ns) + cp_unit(si) * ((n - u[k]) * ts);\n jb[k] = row;\n }\n }\n }\n var y = vec3<f32>(0.0); var ey = vec3<f32>(0.0);\n var mj = array<vec3<f32>, 3>(vec3<f32>(0.0), vec3<f32>(0.0), vec3<f32>(0.0));\n for (var r = 0u; r < 3u; r = r + 1u) {\n let m = cp_m(r);\n y[r] = cp_dot(m, b);\n ey[r] = cp_dot(abs(m), 3.0 * CP_E * abs(b) + vec3<f32>(eb));\n mj[r] = m.x * jb[0] + m.y * jb[1] + m.z * jb[2];\n }\n // Tone (luminance curve, positive Reinhard or identity).\n var z = y;\n var jt = array<vec3<f32>, 3>(vec3<f32>(1.0, 0.0, 0.0), vec3<f32>(0.0, 1.0, 0.0), vec3<f32>(0.0, 0.0, 1.0));\n var eta = 0.0;\n let w = cp_w();\n if (cp_luminance()) {\n let l = cp_dot(w, y);\n let el = cp_dot(abs(w), ey) + 4.0 * CP_E * cp_dot(abs(w), abs(y));\n if (cp_k(${C.ratioAtZero}u) != 1.0 && abs(l) <= el) { node.flag = true; }\n if (l > 0.0) {\n let q = cp_ratio(l);\n eta = q.z;\n z = y * q.x;\n for (var k = 0u; k < 3u; k = k + 1u) { jt[k] = cp_unit(k) * q.x + w * (y[k] * q.y); }\n }\n } else if (cp_k(${C.tone}u) == 1.0) {\n for (var k = 0u; k < 3u; k = k + 1u) { if (y[k] > 0.0) { z[k] = y[k] / (1.0 + y[k]); jt[k] = cp_unit(k) / ((1.0 + y[k]) * (1.0 + y[k])); } }\n }\n var ez = vec3<f32>(0.0);\n for (var k = 0u; k < 3u; k = k + 1u) { ez[k] = cp_dot(abs(jt[k]), ey) + abs(z[k]) * (eta + 4.0) * CP_E; }\n // Desaturation toward the luminance (#601).\n var jz = array<vec3<f32>, 3>(vec3<f32>(1.0, 0.0, 0.0), vec3<f32>(0.0, 1.0, 0.0), vec3<f32>(0.0, 0.0, 1.0));\n let ti = select(select(2u, 1u, z.y > z.z), select(2u, 0u, z.x > z.z), z.x > z.y);\n let zt = z[ti];\n if (cp_desaturate() && zt > 1.0) {\n let lp = cp_dot(w, z);\n if (lp >= 1.0) {\n node.out = vec3<f32>(1.0);\n node.err = vec3<f32>(0.0);\n return node;\n }\n let d = zt - lp;\n let a = (1.0 - lp) / d;\n for (var k = 0u; k < 3u; k = k + 1u) {\n let da = (-w * d - (1.0 - lp) * (cp_unit(ti) - w)) / (d * d);\n jz[k] = w * (1.0 - a) + cp_unit(k) * a + (z[k] - lp) * da;\n }\n z = lp + a * (z - lp);\n var ez2 = vec3<f32>(0.0);\n for (var k = 0u; k < 3u; k = k + 1u) { ez2[k] = cp_dot(abs(jz[k]), ez) + 8.0 * CP_E * (1.0 + abs(z[k])); }\n ez = ez2;\n }\n node.out = clamp(z, vec3<f32>(0.0), vec3<f32>(1.0));\n node.err = ez;\n var jo = array<vec3<f32>, 3>(vec3<f32>(0.0), vec3<f32>(0.0), vec3<f32>(0.0));\n for (var k = 0u; k < 3u; k = k + 1u) {\n if (z[k] > 0.0 && z[k] < 1.0) { jo[k] = jz[k].x * jt[0] + jz[k].y * jt[1] + jz[k].z * jt[2]; }\n }\n node.t0 = jo[0].x * mj[0] + jo[0].y * mj[1] + jo[0].z * mj[2];\n node.t1 = jo[1].x * mj[0] + jo[1].y * mj[1] + jo[1].z * mj[2];\n node.t2 = jo[2].x * mj[0] + jo[2].y * mj[1] + jo[2].z * mj[2];\n return node;\n}\nfn cp_chain(cm: vec3<f32>, c00: f32, c01: f32, c02: f32, c11: f32, c12: f32, c22: f32, dcm: vec3<f32>, dcv: vec3<f32>) -> CpOut {\n let l00 = sqrt(max(0.0, c00));\n let l10 = select(0.0, c01 / l00, l00 > 0.0);\n let l20 = select(0.0, c02 / l00, l00 > 0.0);\n let l11 = sqrt(max(0.0, c11 - l10 * l10));\n let l21 = select(0.0, (c12 - l20 * l10) / l11, l11 > 0.0);\n let l22 = sqrt(max(0.0, c22 - l20 * l20 - l21 * l21));\n let any_noise = l00 > 0.0 || l11 > 0.0 || l22 > 0.0;\n let second_axis = l11 > 0.0 || l21 != 0.0 || l22 > 0.0;\n let n = select(1u, u32(cp_k(${C.chainPoints}u)), any_noise);\n let nj = select(1u, n, second_axis);\n let nk = select(1u, n, l22 > 0.0);\n let centre = cp_develop(cm).out;\n var t: CpOut;\n var e = vec3<f32>(0.0); var q = vec3<f32>(0.0); var count = 0.0;\n for (var i = 0u; i < n; i = i + 1u) {\n let x0 = select(0.0, cp_k(${C.chainX}u + i), any_noise);\n let wi = select(1.0, cp_k(${C.chainW}u + i), any_noise);\n for (var jj = 0u; jj < nj; jj = jj + 1u) {\n let x1 = select(0.0, cp_k(${C.chainX}u + jj), second_axis);\n let wj = select(wi, wi * cp_k(${C.chainW}u + jj), second_axis);\n for (var kk = 0u; kk < nk; kk = kk + 1u) {\n let x2 = select(0.0, cp_k(${C.chainX}u + kk), l22 > 0.0);\n let weight = select(wj, wj * cp_k(${C.chainW}u + kk), l22 > 0.0);\n let c = vec3<f32>(cm.x + l00 * x0, cm.y + l10 * x0 + l11 * x1, cm.z + l20 * x0 + l21 * x1 + l22 * x2);\n let dc = 3.0 * CP_E * (abs(cm) + vec3<f32>(abs(l00 * x0), abs(l10 * x0) + abs(l11 * x1), abs(l20 * x0) + abs(l21 * x1) + abs(l22 * x2)));\n let node = cp_develop(c);\n if (node.flag) { t.flag = true; }\n // #605: a node within its bound of the neighbor rebuild's threshold (where a channel is kept or rebuilt).\n if (nb_on() && any(abs(c - vec3<f32>(NB_H)) <= dc + dcm + 5.0 * (sqrt(dcv.x) + sqrt(dcv.y) + sqrt(dcv.z)) + 16.0 * CP_E)) { t.flag = true; }\n count = count + 1.0;\n let d = node.out - centre;\n e = e + weight * node.out;\n q = q + weight * (d * d);\n t.a0 = t.a0 + weight * node.t0; t.a1 = t.a1 + weight * node.t1; t.a2 = t.a2 + weight * node.t2;\n let err = node.err + vec3<f32>(cp_dot(abs(node.t0), dc), cp_dot(abs(node.t1), dc), cp_dot(abs(node.t2), dc));\n t.bm = t.bm + weight * err;\n t.bv = t.bv + 2.0 * (weight * err);\n }\n }\n }\n let shifted = e - centre;\n t.hm = e;\n t.hv = max(vec3<f32>(0.0), q - shifted * shifted);\n let rows = array<vec3<f32>, 3>(abs(t.a0), abs(t.a1), abs(t.a2));\n for (var k = 0u; k < 3u; k = k + 1u) {\n t.bm[k] = t.bm[k] + count * CP_E * abs(e[k]) + cp_dot(rows[k], dcm) + 0.8 * cp_dot(rows[k], sqrt(dcv));\n t.bv[k] = t.bv[k] + count * CP_E * q[k] + 2.0 * abs(shifted[k]) * t.bm[k] + cp_dot(rows[k] * rows[k], dcv);\n }\n t.ju = (4.0 * count + 64.0) * CP_E;\n return t;\n}\n`;\n\n/** The coupled steps' text with the neighbor reconstruction's functions (#605): the full form with it, else the off form. */\nexport const displayViewCoupledWgsl = (neighbors: boolean): string => DISPLAY_VIEW_COUPLED_WGSL + displayViewNeighborsWgsl(neighbors);\n\n/** The host's coupled-constants buffer of a view (`DISPLAY_VIEW_COUPLED` layout), or the one-word stub buffer. */\nexport function displayViewCoupledConstants(setup: {\n gains: readonly number[]; clipLevel: number; matrix: readonly (readonly number[])[];\n rendering?: { toneCurve: string; toneCurveParameters?: { whiteLuminance: number } | { exponent: number; semiSaturation: number; whiteLuminance: number }; highlightMode: string; gamutHandling: string; fast: boolean };\n coupled?: { chainRule: { x: Float64Array; w: Float64Array }; luminanceRule: { x: Float64Array; w: Float64Array }; ratioAtZero: number; luminanceTone: boolean };\n}, weights: readonly number[], legendre: { x: ArrayLike<number>; w: ArrayLike<number> }): Float32Array<ArrayBuffer> {\n const r = setup.rendering, k = setup.coupled;\n if (!r || !k) return new Float32Array(1);\n const out = new Float32Array(C.size), p = r.toneCurveParameters;\n out[C.on] = 1; out[C.luminance] = k.luminanceTone ? 1 : 0;\n out[C.tone] = r.toneCurve === \"extended-reinhard-luminance\" ? 2 : r.toneCurve === \"naka-rushton-luminance\" ? 3 : r.toneCurve === \"positive-reinhard-per-channel\" ? 1 : 0;\n if (p && \"exponent\" in p) {\n out[C.a] = p.semiSaturation; out[C.n] = p.exponent; out[C.inverseWhite] = 1 + (p.semiSaturation / p.whiteLuminance) ** p.exponent;\n } else if (p) out[C.a] = 1 / (p.whiteLuminance * p.whiteLuminance);\n out[C.ratioAtZero] = k.ratioAtZero === Infinity ? DISPLAY_VIEW_COUPLED_INFINITE_RATIO : k.ratioAtZero;\n out.set(weights, C.weights);\n out[C.reconstruct] = r.highlightMode.startsWith(\"reconstruct\") ? 1 : 0; out[C.desaturate] = r.gamutHandling === \"desaturate-to-luminance\" ? 1 : 0; out[C.fast] = r.fast ? 1 : 0;\n out.set(setup.gains, C.gains); out[C.clipLevel] = setup.clipLevel; out.set(setup.matrix.flat(), C.matrix);\n out[C.chainPoints] = k.chainRule.x.length; out.set(k.chainRule.x, C.chainX); out.set(k.chainRule.w, C.chainW);\n out.set(k.luminanceRule.x, C.hermiteX); out.set(k.luminanceRule.w, C.hermiteW);\n out.set(Array.from(legendre.x), C.legendreX); out.set(Array.from(legendre.w), C.legendreW);\n return out;\n}\n"]}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * #605 (2.23.0): `highlightMode: "reconstruct-neighbors"` (#602) in the display view's GPU kernels, Speed and Quality, fast and
3
+ * full. The highlight step of the coupled chain (`cp_develop` in wgsl-display-view-coupled.ts) becomes the rebuild of
4
+ * src/color/neighbor-highlight-reconstruction.ts (`rebuildClippedPixel`, `nb_rebuild` below), with each real pixel's region
5
+ * ratios ρ from the host.
6
+ *
7
+ * **The ratios are found on the host and uploaded** (docs/WEBGPU.md, "Neighbor highlight reconstruction"): the reference's own
8
+ * float64 code (`DisplayViewCoupledRendering.ratioAt`: the noise-free channels, the 8-connected clipped regions widened by the
9
+ * margin, the ring's mean ratios fast or their harmonic fill by SOR full) gives ρ for exactly the real pixels whose chain needs
10
+ * them, so every region decision is the reference's and ρ carries one float32 rounding. They travel in the band's flag buffer
11
+ * after its flag words (no binding is added; the kernels stay within the 8 storage buffers per stage): one word per display
12
+ * pixel (the offset of its block, `MISSING` or `SKIP`) and per block 3 floats for each real pixel of the footprint.
13
+ *
14
+ * Two dispatches per band: the first runs with every offset `MISSING`; a pixel whose chain needs a ratio skips the chain and
15
+ * sets `DISPLAY_VIEW_NEIGHBORS_FLAG`. The host then computes the ratios of those pixels' footprints and runs the band again
16
+ * with the other pixels `SKIP` (they return at once, so their first results stay in the output buffer). The kernels' default (`DISPLAY_VIEW_NEIGHBORS_STUB_WGSL`, wgsl-display-view-coupled-stub.ts)
17
+ * computes every pixel in one dispatch.
18
+ *
19
+ * Bounds (first order, as the coupled steps', E = 2⁻²³): the rebuild's roundings, at most 10E of the largest rebuilt channel
20
+ * (the products u = c·g, the sums of the kept channels and ratios, the quotient's 2.5E, the product s·ρ and ρ's own upload
21
+ * rounding through ∂b/∂ρ, ≤ E·|b|), enter the chain where the blend's 8E did; the rebuild is continuous except where a channel
22
+ * crosses the threshold (kept or clipped), so a node within its rounding, the channel mean's bound and the variance's (√δ
23
+ * times 5, beyond the largest Gauss–Hermite node) of the threshold flags the display pixel for the host's reference.
24
+ */
25
+ import type { DisplayViewSetup } from "../facade/display-view.js";
26
+ /** The display-pixel flag bit of a chain that needed ratios the host had not given yet (both kernels' first flag word). */
27
+ export declare const DISPLAY_VIEW_NEIGHBORS_FLAG = 128;
28
+ /** The coupled steps' neighbor functions in a view without the reconstruction (with the kernels' stub). */
29
+ export declare const DISPLAY_VIEW_NEIGHBORS_OFF_WGSL: string;
30
+ /** The full form (with the coupled steps' text; it uses `CP_E`, `cp_unit`, `flags` and `params.count`). */
31
+ export declare const DISPLAY_VIEW_NEIGHBORS_WGSL: string;
32
+ /** The coupled steps' neighbor functions: the full form with the reconstruction, else the off form. */
33
+ export declare const displayViewNeighborsWgsl: (on: boolean) => string;
34
+ /** Test hook (#605): the last render's ratio work: the dispatches, the pixels and real pixels given ratios, and the host's milliseconds. */
35
+ export declare const displayViewNeighborStats: {
36
+ dispatches: number;
37
+ pixels: number;
38
+ realPixels: number;
39
+ hostMilliseconds: number;
40
+ };
41
+ /**
42
+ * Runs one band's pixel dispatch with the ratios (see the module notes). `run` dispatches the band with the given flag-buffer
43
+ * contents (its flag words first) and returns the flag words read back; the output buffer is the band's own across the calls.
44
+ * `geometry` is the kernels' axis records (columns, then rows; both kernels' stride of 20 words). Returns the final flag words.
45
+ */
46
+ export declare function dispatchWithNeighborRatios(setup: DisplayViewSetup, geometry: Float32Array, first: number, count: number, limitBytes: number, run: (flags: Uint32Array<ArrayBuffer>) => Promise<Uint32Array>): Promise<Uint32Array>;
@@ -0,0 +1,114 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ import { DISPLAY_VIEW_NEIGHBORS_STUB_WGSL } from "./wgsl-display-view-coupled-stub.js";
3
+ import { DISPLAY_VIEW_GEOMETRY_STRIDE as stride } from "./wgsl-display-view-speed-kernel.js";
4
+ /** The display-pixel flag bit of a chain that needed ratios the host had not given yet (both kernels' first flag word). */
5
+ export const DISPLAY_VIEW_NEIGHBORS_FLAG = 128;
6
+ const MISSING = 0xffffffff, SKIP = 0xfffffffe, FLAG_WORDS = 3;
7
+ const COMMON = /* wgsl */ `
8
+ const NB_H: f32 = 0.98;
9
+ struct NbOut { b: vec3<f32>, j0: vec3<f32>, j1: vec3<f32>, j2: vec3<f32>, err: f32 };
10
+ `;
11
+ /** The coupled steps' neighbor functions in a view without the reconstruction (with the kernels' stub). */
12
+ export const DISPLAY_VIEW_NEIGHBORS_OFF_WGSL = COMMON + DISPLAY_VIEW_NEIGHBORS_STUB_WGSL + /* wgsl */ `
13
+ fn nb_on() -> bool { return false; }
14
+ fn nb_rebuild(c: vec3<f32>, g: vec3<f32>) -> NbOut { var o: NbOut; return o; }
15
+ `;
16
+ /** The full form (with the coupled steps' text; it uses `CP_E`, `cp_unit`, `flags` and `params.count`). */
17
+ export const DISPLAY_VIEW_NEIGHBORS_WGSL = COMMON + /* wgsl */ `
18
+ var<private> nb_rho: vec3<f32>;
19
+ var<private> nb_need: bool;
20
+ fn nb_on() -> bool { return true; }
21
+ fn nb_skip(i: u32) -> bool { return flags[3u * params.count + i] == 0xfffffffeu; }
22
+ fn nb_ratio(i: u32, r: u32) -> bool {
23
+ let o = flags[3u * params.count + i];
24
+ if (o >= 0xfffffffeu) { nb_need = true; return false; }
25
+ let p = o + 3u * r;
26
+ nb_rho = vec3<f32>(bitcast<f32>(flags[p]), bitcast<f32>(flags[p + 1u]), bitcast<f32>(flags[p + 2u]));
27
+ return true;
28
+ }
29
+ fn nb_flag() -> u32 { return select(0u, 128u, nb_need); }
30
+ fn nb_max(v: vec3<f32>) -> f32 { return max(abs(v.x), max(abs(v.y), abs(v.z))); }
31
+ fn nb_rebuild(c: vec3<f32>, g: vec3<f32>) -> NbOut {
32
+ let u = c * g;
33
+ let r = nb_rho;
34
+ var j = array<vec3<f32>, 3>(vec3<f32>(g.x, 0.0, 0.0), vec3<f32>(0.0, g.y, 0.0), vec3<f32>(0.0, 0.0, g.z));
35
+ var b = u;
36
+ let k = c < vec3<f32>(NB_H);
37
+ var e = 1.0;
38
+ if (!all(k) && !(r.x < 0.0)) {
39
+ if (!any(k)) {
40
+ let q = select(vec3<f32>(0.0), u / select(vec3<f32>(1.0), r, r > vec3<f32>(0.0)), r > vec3<f32>(0.0));
41
+ let m = select(select(2u, 1u, q.y > q.z), select(2u, 0u, q.x > q.z), q.x > q.y);
42
+ b = q[m] * r;
43
+ for (var n = 0u; n < 3u; n = n + 1u) { j[n] = vec3<f32>(0.0); if (r[m] > 0.0) { j[n] = cp_unit(m) * (r[n] * g[m] / r[m]); } }
44
+ e = 6.0;
45
+ } else {
46
+ let ku = select(vec3<f32>(0.0), u, k);
47
+ let kr = select(vec3<f32>(0.0), r, k);
48
+ let su = (ku.x + ku.y) + ku.z;
49
+ let sr = (kr.x + kr.y) + kr.z;
50
+ let s = select(0.0, su / select(1.0, sr, sr > 0.0), sr > 0.0);
51
+ for (var n = 0u; n < 3u; n = n + 1u) {
52
+ let t = s * r[n];
53
+ if (!k[n] && t > u[n]) { b[n] = t; j[n] = vec3<f32>(0.0); if (sr > 0.0) { j[n] = select(vec3<f32>(0.0), r[n] * g / sr, k); } }
54
+ }
55
+ e = 10.0;
56
+ }
57
+ }
58
+ return NbOut(b, j[0], j[1], j[2], e * CP_E * nb_max(b));
59
+ }
60
+ `;
61
+ /** The coupled steps' neighbor functions: the full form with the reconstruction, else the off form. */
62
+ export const displayViewNeighborsWgsl = (on) => on ? DISPLAY_VIEW_NEIGHBORS_WGSL : DISPLAY_VIEW_NEIGHBORS_OFF_WGSL;
63
+ /** Test hook (#605): the last render's ratio work: the dispatches, the pixels and real pixels given ratios, and the host's milliseconds. */
64
+ export const displayViewNeighborStats = { dispatches: 0, pixels: 0, realPixels: 0, hostMilliseconds: 0 };
65
+ /**
66
+ * Runs one band's pixel dispatch with the ratios (see the module notes). `run` dispatches the band with the given flag-buffer
67
+ * contents (its flag words first) and returns the flag words read back; the output buffer is the band's own across the calls.
68
+ * `geometry` is the kernels' axis records (columns, then rows; both kernels' stride of 20 words). Returns the final flag words.
69
+ */
70
+ export async function dispatchWithNeighborRatios(setup, geometry, first, count, limitBytes, run) {
71
+ const coupled = setup.coupled, ints = new Int32Array(geometry.buffer, geometry.byteOffset, geometry.length), width = setup.region.width, rho = new Float64Array(3);
72
+ const start = new Uint32Array((FLAG_WORDS + 1) * count);
73
+ start.fill(MISSING, FLAG_WORDS * count);
74
+ let flags = await run(start);
75
+ displayViewNeighborStats.dispatches++;
76
+ let pending = [];
77
+ for (let i = 0; i < count; i++)
78
+ if ((flags[FLAG_WORDS * i] & DISPLAY_VIEW_NEIGHBORS_FLAG) !== 0)
79
+ pending.push(i);
80
+ if (pending.length > 0)
81
+ coupled.bindView(setup);
82
+ while (pending.length > 0) {
83
+ const t0 = performance.now(), words = Array.from(flags.subarray(0, FLAG_WORDS * count)), offsets = new Array(count).fill(SKIP), data = [];
84
+ const header = (FLAG_WORDS + 1) * count, floats = new Float32Array(1), bits = new Uint32Array(floats.buffer);
85
+ let taken = 0;
86
+ for (; taken < pending.length; taken++) {
87
+ const i = pending[taken], p = first + i, rx = p % width, ry = (p - rx) / width, col = rx * stride, row = (width + ry) * stride, nx = ints[col + 1], ny = ints[row + 1];
88
+ if (taken > 0 && 4 * (header + data.length + 3 * nx * ny) > limitBytes)
89
+ break;
90
+ offsets[i] = header + data.length;
91
+ for (let j = 0; j < ny; j++)
92
+ for (let ii = 0; ii < nx; ii++) {
93
+ coupled.ratioAt(ints[col] + ii + setup.margin, ints[row] + j + setup.margin, rho);
94
+ for (let c = 0; c < 3; c++) {
95
+ floats[0] = rho[c];
96
+ data.push(bits[0]);
97
+ }
98
+ }
99
+ displayViewNeighborStats.realPixels += nx * ny;
100
+ }
101
+ displayViewNeighborStats.pixels += taken;
102
+ const contents = Uint32Array.from([...words, ...offsets, ...data]);
103
+ displayViewNeighborStats.hostMilliseconds += performance.now() - t0;
104
+ flags = await run(contents);
105
+ displayViewNeighborStats.dispatches++;
106
+ pending = pending.slice(taken);
107
+ }
108
+ // A pixel still without its ratios cannot happen; it would take the host's reference (flag bit 0).
109
+ for (let i = 0; i < count; i++)
110
+ if ((flags[FLAG_WORDS * i] & DISPLAY_VIEW_NEIGHBORS_FLAG) !== 0)
111
+ flags[FLAG_WORDS * i] = flags[FLAG_WORDS * i] | 1;
112
+ return flags;
113
+ }
114
+ //# sourceMappingURL=wgsl-display-view-neighbors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wgsl-display-view-neighbors.js","sourceRoot":"","sources":["../../src/gpu/wgsl-display-view-neighbors.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * #605 (2.23.0): `highlightMode: \"reconstruct-neighbors\"` (#602) in the display view's GPU kernels, Speed and Quality, fast and\n * full. The highlight step of the coupled chain (`cp_develop` in wgsl-display-view-coupled.ts) becomes the rebuild of\n * src/color/neighbor-highlight-reconstruction.ts (`rebuildClippedPixel`, `nb_rebuild` below), with each real pixel's region\n * ratios ρ from the host.\n *\n * **The ratios are found on the host and uploaded** (docs/WEBGPU.md, \"Neighbor highlight reconstruction\"): the reference's own\n * float64 code (`DisplayViewCoupledRendering.ratioAt`: the noise-free channels, the 8-connected clipped regions widened by the\n * margin, the ring's mean ratios fast or their harmonic fill by SOR full) gives ρ for exactly the real pixels whose chain needs\n * them, so every region decision is the reference's and ρ carries one float32 rounding. They travel in the band's flag buffer\n * after its flag words (no binding is added; the kernels stay within the 8 storage buffers per stage): one word per display\n * pixel (the offset of its block, `MISSING` or `SKIP`) and per block 3 floats for each real pixel of the footprint.\n *\n * Two dispatches per band: the first runs with every offset `MISSING`; a pixel whose chain needs a ratio skips the chain and\n * sets `DISPLAY_VIEW_NEIGHBORS_FLAG`. The host then computes the ratios of those pixels' footprints and runs the band again\n * with the other pixels `SKIP` (they return at once, so their first results stay in the output buffer). The kernels' default (`DISPLAY_VIEW_NEIGHBORS_STUB_WGSL`, wgsl-display-view-coupled-stub.ts)\n * computes every pixel in one dispatch.\n *\n * Bounds (first order, as the coupled steps', E = 2⁻²³): the rebuild's roundings, at most 10E of the largest rebuilt channel\n * (the products u = c·g, the sums of the kept channels and ratios, the quotient's 2.5E, the product s·ρ and ρ's own upload\n * rounding through ∂b/∂ρ, ≤ E·|b|), enter the chain where the blend's 8E did; the rebuild is continuous except where a channel\n * crosses the threshold (kept or clipped), so a node within its rounding, the channel mean's bound and the variance's (√δ\n * times 5, beyond the largest Gauss–Hermite node) of the threshold flags the display pixel for the host's reference.\n */\n\nimport type { DisplayViewSetup } from \"../facade/display-view.js\";\nimport { DISPLAY_VIEW_NEIGHBORS_STUB_WGSL } from \"./wgsl-display-view-coupled-stub.js\";\nimport { DISPLAY_VIEW_GEOMETRY_STRIDE as stride } from \"./wgsl-display-view-speed-kernel.js\";\n\n/** The display-pixel flag bit of a chain that needed ratios the host had not given yet (both kernels' first flag word). */\nexport const DISPLAY_VIEW_NEIGHBORS_FLAG = 128;\nconst MISSING = 0xffffffff, SKIP = 0xfffffffe, FLAG_WORDS = 3;\n\nconst COMMON = /* wgsl */ `\nconst NB_H: f32 = 0.98;\nstruct NbOut { b: vec3<f32>, j0: vec3<f32>, j1: vec3<f32>, j2: vec3<f32>, err: f32 };\n`;\n/** The coupled steps' neighbor functions in a view without the reconstruction (with the kernels' stub). */\nexport const DISPLAY_VIEW_NEIGHBORS_OFF_WGSL = COMMON + DISPLAY_VIEW_NEIGHBORS_STUB_WGSL + /* wgsl */ `\nfn nb_on() -> bool { return false; }\nfn nb_rebuild(c: vec3<f32>, g: vec3<f32>) -> NbOut { var o: NbOut; return o; }\n`;\n/** The full form (with the coupled steps' text; it uses `CP_E`, `cp_unit`, `flags` and `params.count`). */\nexport const DISPLAY_VIEW_NEIGHBORS_WGSL = COMMON + /* wgsl */ `\nvar<private> nb_rho: vec3<f32>;\nvar<private> nb_need: bool;\nfn nb_on() -> bool { return true; }\nfn nb_skip(i: u32) -> bool { return flags[3u * params.count + i] == 0xfffffffeu; }\nfn nb_ratio(i: u32, r: u32) -> bool {\n let o = flags[3u * params.count + i];\n if (o >= 0xfffffffeu) { nb_need = true; return false; }\n let p = o + 3u * r;\n nb_rho = vec3<f32>(bitcast<f32>(flags[p]), bitcast<f32>(flags[p + 1u]), bitcast<f32>(flags[p + 2u]));\n return true;\n}\nfn nb_flag() -> u32 { return select(0u, 128u, nb_need); }\nfn nb_max(v: vec3<f32>) -> f32 { return max(abs(v.x), max(abs(v.y), abs(v.z))); }\nfn nb_rebuild(c: vec3<f32>, g: vec3<f32>) -> NbOut {\n let u = c * g;\n let r = nb_rho;\n var j = array<vec3<f32>, 3>(vec3<f32>(g.x, 0.0, 0.0), vec3<f32>(0.0, g.y, 0.0), vec3<f32>(0.0, 0.0, g.z));\n var b = u;\n let k = c < vec3<f32>(NB_H);\n var e = 1.0;\n if (!all(k) && !(r.x < 0.0)) {\n if (!any(k)) {\n let q = select(vec3<f32>(0.0), u / select(vec3<f32>(1.0), r, r > vec3<f32>(0.0)), r > vec3<f32>(0.0));\n let m = select(select(2u, 1u, q.y > q.z), select(2u, 0u, q.x > q.z), q.x > q.y);\n b = q[m] * r;\n for (var n = 0u; n < 3u; n = n + 1u) { j[n] = vec3<f32>(0.0); if (r[m] > 0.0) { j[n] = cp_unit(m) * (r[n] * g[m] / r[m]); } }\n e = 6.0;\n } else {\n let ku = select(vec3<f32>(0.0), u, k);\n let kr = select(vec3<f32>(0.0), r, k);\n let su = (ku.x + ku.y) + ku.z;\n let sr = (kr.x + kr.y) + kr.z;\n let s = select(0.0, su / select(1.0, sr, sr > 0.0), sr > 0.0);\n for (var n = 0u; n < 3u; n = n + 1u) {\n let t = s * r[n];\n if (!k[n] && t > u[n]) { b[n] = t; j[n] = vec3<f32>(0.0); if (sr > 0.0) { j[n] = select(vec3<f32>(0.0), r[n] * g / sr, k); } }\n }\n e = 10.0;\n }\n }\n return NbOut(b, j[0], j[1], j[2], e * CP_E * nb_max(b));\n}\n`;\n\n/** The coupled steps' neighbor functions: the full form with the reconstruction, else the off form. */\nexport const displayViewNeighborsWgsl = (on: boolean): string => on ? DISPLAY_VIEW_NEIGHBORS_WGSL : DISPLAY_VIEW_NEIGHBORS_OFF_WGSL;\n\n/** Test hook (#605): the last render's ratio work: the dispatches, the pixels and real pixels given ratios, and the host's milliseconds. */\nexport const displayViewNeighborStats = { dispatches: 0, pixels: 0, realPixels: 0, hostMilliseconds: 0 };\n\n/**\n * Runs one band's pixel dispatch with the ratios (see the module notes). `run` dispatches the band with the given flag-buffer\n * contents (its flag words first) and returns the flag words read back; the output buffer is the band's own across the calls.\n * `geometry` is the kernels' axis records (columns, then rows; both kernels' stride of 20 words). Returns the final flag words.\n */\nexport async function dispatchWithNeighborRatios(setup: DisplayViewSetup, geometry: Float32Array, first: number, count: number, limitBytes: number,\n run: (flags: Uint32Array<ArrayBuffer>) => Promise<Uint32Array>): Promise<Uint32Array> {\n const coupled = setup.coupled!, ints = new Int32Array(geometry.buffer, geometry.byteOffset, geometry.length), width = setup.region.width, rho = new Float64Array(3);\n const start = new Uint32Array((FLAG_WORDS + 1) * count);\n start.fill(MISSING, FLAG_WORDS * count);\n let flags = await run(start);\n displayViewNeighborStats.dispatches++;\n let pending: number[] = [];\n for (let i = 0; i < count; i++) if ((flags[FLAG_WORDS * i]! & DISPLAY_VIEW_NEIGHBORS_FLAG) !== 0) pending.push(i);\n if (pending.length > 0) coupled.bindView!(setup);\n while (pending.length > 0) {\n const t0 = performance.now(), words: number[] = Array.from(flags.subarray(0, FLAG_WORDS * count)), offsets = new Array<number>(count).fill(SKIP), data: number[] = [];\n const header = (FLAG_WORDS + 1) * count, floats = new Float32Array(1), bits = new Uint32Array(floats.buffer);\n let taken = 0;\n for (; taken < pending.length; taken++) {\n const i = pending[taken]!, p = first + i, rx = p % width, ry = (p - rx) / width, col = rx * stride, row = (width + ry) * stride, nx = ints[col + 1]!, ny = ints[row + 1]!;\n if (taken > 0 && 4 * (header + data.length + 3 * nx * ny) > limitBytes) break;\n offsets[i] = header + data.length;\n for (let j = 0; j < ny; j++) for (let ii = 0; ii < nx; ii++) {\n coupled.ratioAt!(ints[col]! + ii + setup.margin, ints[row]! + j + setup.margin, rho);\n for (let c = 0; c < 3; c++) { floats[0] = rho[c]!; data.push(bits[0]!); }\n }\n displayViewNeighborStats.realPixels += nx * ny;\n }\n displayViewNeighborStats.pixels += taken;\n const contents = Uint32Array.from([...words, ...offsets, ...data]);\n displayViewNeighborStats.hostMilliseconds += performance.now() - t0;\n flags = await run(contents);\n displayViewNeighborStats.dispatches++;\n pending = pending.slice(taken);\n }\n // A pixel still without its ratios cannot happen; it would take the host's reference (flag bit 0).\n for (let i = 0; i < count; i++) if ((flags[FLAG_WORDS * i]! & DISPLAY_VIEW_NEIGHBORS_FLAG) !== 0) flags[FLAG_WORDS * i] = flags[FLAG_WORDS * i]! | 1;\n return flags;\n}\n"]}
@@ -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
@@ -51,8 +45,10 @@ export declare const DISPLAY_VIEW_QUALITY_FLAG: Readonly<{
51
45
  ahdChoice: 32;
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;
48
+ /** #605: a chain needed neighbor ratios the host had not given (redone with them; the host sets bit 0 if any is left). */
49
+ neighborRatios: 128;
54
50
  /** The bits that require the host's recomputation. */
55
- recompute: 47;
51
+ recompute: 35;
56
52
  }>;
57
53
  /** #533: flag words per display pixel: the flags, then the 36-bit mask of saturated real pixels. */
58
54
  export declare const DISPLAY_VIEW_QUALITY_FLAG_WORDS = 3;
@@ -62,8 +58,6 @@ export declare const DISPLAY_VIEW_QUALITY_FLAG_WORDS = 3;
62
58
  * 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
59
  */
64
60
  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
61
  /**
68
62
  * A site whose uncertain lattice points (the material module's flag) could move its electrons by more than this fraction of
69
63
  * their value is flagged for host recomputation; a smaller uncertainty enters the site's bound instead (the tap weights times
@@ -120,6 +114,9 @@ export declare const DISPLAY_VIEW_QUALITY_SITES_WGSL: string;
120
114
  */
121
115
  export declare const DISPLAY_VIEW_QUALITY_SITES_BLOCKED_WGSL: string;
122
116
  /** Pass 3: the display pixels (see the module comment). */
117
+ export declare const DISPLAY_VIEW_QUALITY_PIXELS_BODY_WGSL: string;
118
+ /** The pixel pass (`DISPLAY_VIEW_QUALITY_PIXELS_BODY_WGSL`) with the coupled steps' text: the stub by default, the coupled steps on demand (#593). */
119
+ export declare function assembleDisplayViewQualityPixelsWgsl(coupledWgsl?: string): string;
123
120
  export declare const DISPLAY_VIEW_QUALITY_PIXELS_WGSL: string;
124
121
  /** The lattice pass with a material module appended (`fn material_at(p: vec2<f32>) -> u32`, `var<private> material_uncertain: bool`). */
125
122
  export declare function assembleDisplayViewQualityLatticeWgsl(materialModuleWgsl: string): string;