@photivra/engine 2.15.0 → 2.17.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 (119) hide show
  1. package/CHANGELOG.md +102 -1
  2. package/CITATION.cff +1 -1
  3. package/README.md +6 -6
  4. package/SECURITY.md +1 -1
  5. package/THIRD_PARTY.md +38 -0
  6. package/dist/camera/lens-projection.d.ts +5 -0
  7. package/dist/camera/lens-projection.js +10 -0
  8. package/dist/camera/lens-projection.js.map +1 -1
  9. package/dist/capture/native-environment-lean.js +1 -1
  10. package/dist/capture/native-environment-lean.js.map +1 -1
  11. package/dist/capture/native-raw-development.d.ts +15 -0
  12. package/dist/capture/native-raw-development.js +12 -6
  13. package/dist/capture/native-raw-development.js.map +1 -1
  14. package/dist/capture/raw-development-kernel.d.ts +10 -3
  15. package/dist/capture/raw-development-kernel.js +25 -6
  16. package/dist/capture/raw-development-kernel.js.map +1 -1
  17. package/dist/core/internal-radiance-evaluator.d.ts +5 -2
  18. package/dist/core/internal-radiance-evaluator.js.map +1 -1
  19. package/dist/core/version.d.ts +1 -1
  20. package/dist/core/version.js +1 -1
  21. package/dist/core/version.js.map +1 -1
  22. package/dist/equipment/generic-lens-catalogue.d.ts +227 -0
  23. package/dist/equipment/generic-lens-catalogue.js +243 -0
  24. package/dist/equipment/generic-lens-catalogue.js.map +1 -0
  25. package/dist/facade/defocus-bokeh-zones.d.ts +33 -0
  26. package/dist/facade/defocus-bokeh-zones.js +53 -0
  27. package/dist/facade/defocus-bokeh-zones.js.map +1 -0
  28. package/dist/facade/defocus-image-space-provider.d.ts +118 -0
  29. package/dist/facade/defocus-image-space-provider.js +448 -0
  30. package/dist/facade/defocus-image-space-provider.js.map +1 -0
  31. package/dist/facade/diffraction-provider.d.ts +45 -0
  32. package/dist/facade/diffraction-provider.js +120 -14
  33. package/dist/facade/diffraction-provider.js.map +1 -1
  34. package/dist/facade/display-view-gpu-session.js +4 -0
  35. package/dist/facade/display-view-gpu-session.js.map +1 -1
  36. package/dist/facade/display-view-gpu.d.ts +10 -0
  37. package/dist/facade/display-view-gpu.js.map +1 -1
  38. package/dist/facade/display-view-lens-signal.d.ts +30 -0
  39. package/dist/facade/display-view-lens-signal.js +427 -0
  40. package/dist/facade/display-view-lens-signal.js.map +1 -0
  41. package/dist/facade/display-view.d.ts +21 -0
  42. package/dist/facade/display-view.js +66 -8
  43. package/dist/facade/display-view.js.map +1 -1
  44. package/dist/facade/expected-signal-setup.d.ts +7 -0
  45. package/dist/facade/expected-signal-setup.js +12 -2
  46. package/dist/facade/expected-signal-setup.js.map +1 -1
  47. package/dist/facade/expected-signal.d.ts +8 -0
  48. package/dist/facade/expected-signal.js +150 -0
  49. package/dist/facade/expected-signal.js.map +1 -1
  50. package/dist/facade/generic-lens-capture.d.ts +6 -0
  51. package/dist/facade/generic-lens-capture.js +8 -0
  52. package/dist/facade/generic-lens-capture.js.map +1 -0
  53. package/dist/facade/large-defocus-lattice.d.ts +39 -0
  54. package/dist/facade/large-defocus-lattice.js +64 -0
  55. package/dist/facade/large-defocus-lattice.js.map +1 -0
  56. package/dist/facade/scene-radiance.d.ts +5 -0
  57. package/dist/facade/scene-radiance.js +5 -2
  58. package/dist/facade/scene-radiance.js.map +1 -1
  59. package/dist/facade/simulate-capture.d.ts +148 -6
  60. package/dist/facade/simulate-capture.js +521 -88
  61. package/dist/facade/simulate-capture.js.map +1 -1
  62. package/dist/facade/simulate-display-view.js +29 -19
  63. package/dist/facade/simulate-display-view.js.map +1 -1
  64. package/dist/gpu/display-view-quality-gpu.d.ts +2 -9
  65. package/dist/gpu/display-view-quality-gpu.js +63 -13
  66. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  67. package/dist/gpu/display-view-speed-gpu.d.ts +2 -0
  68. package/dist/gpu/display-view-speed-gpu.js +47 -16
  69. package/dist/gpu/display-view-speed-gpu.js.map +1 -1
  70. package/dist/gpu/image-kernel-accelerator.js +3 -0
  71. package/dist/gpu/image-kernel-accelerator.js.map +1 -1
  72. package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +4 -0
  73. package/dist/gpu/wgsl-display-view-quality-kernel.js +53 -2
  74. package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
  75. package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +15 -0
  76. package/dist/gpu/wgsl-display-view-speed-kernel.js +42 -1
  77. package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
  78. package/dist/index.d.ts +5 -2
  79. package/dist/index.js +4 -1
  80. package/dist/index.js.map +1 -1
  81. package/dist/optics/defocus-bokeh-kernel.d.ts +207 -0
  82. package/dist/optics/defocus-bokeh-kernel.js +380 -0
  83. package/dist/optics/defocus-bokeh-kernel.js.map +1 -0
  84. package/dist/optics/defocus-disc-kernel.d.ts +44 -21
  85. package/dist/optics/defocus-disc-kernel.js +47 -25
  86. package/dist/optics/defocus-disc-kernel.js.map +1 -1
  87. package/dist/optics/generic-lens-psf.d.ts +68 -0
  88. package/dist/optics/generic-lens-psf.js +337 -0
  89. package/dist/optics/generic-lens-psf.js.map +1 -0
  90. package/dist/optics/illumination-vignetting.d.ts +6 -0
  91. package/dist/optics/illumination-vignetting.js +24 -7
  92. package/dist/optics/illumination-vignetting.js.map +1 -1
  93. package/dist/optics/sensor-environment-query.d.ts +37 -0
  94. package/dist/optics/sensor-environment-query.js +58 -19
  95. package/dist/optics/sensor-environment-query.js.map +1 -1
  96. package/dist/optics/site-kernel-runs.d.ts +77 -0
  97. package/dist/optics/site-kernel-runs.js +200 -0
  98. package/dist/optics/site-kernel-runs.js.map +1 -0
  99. package/dist/output/generic-lens-corrections.d.ts +24 -0
  100. package/dist/output/generic-lens-corrections.js +51 -0
  101. package/dist/output/generic-lens-corrections.js.map +1 -0
  102. package/dist/processing/development-detail.d.ts +132 -0
  103. package/dist/processing/development-detail.js +325 -0
  104. package/dist/processing/development-detail.js.map +1 -0
  105. package/docs/AGENT_GUIDE.md +1 -0
  106. package/docs/API_REFERENCE.md +54 -1
  107. package/docs/QUICK_START.md +444 -26
  108. package/docs/USAGE.md +71 -8
  109. package/docs/api/capture-native-raw-development.md +16 -0
  110. package/docs/api/core-version.md +1 -1
  111. package/docs/api/equipment-generic-lens-catalogue.md +281 -0
  112. package/docs/api/exports.json +162 -2
  113. package/docs/api/facade-simulate-capture.md +151 -5
  114. package/docs/api/optics-defocus-bokeh-kernel.md +145 -0
  115. package/docs/api/optics-defocus-disc-kernel.md +25 -17
  116. package/docs/api/optics-sensor-environment-query.md +6 -0
  117. package/docs/api/output-generic-lens-corrections.md +39 -0
  118. package/llms.txt +1 -0
  119. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-view-lens-signal.js","sourceRoot":"","sources":["../../src/facade/display-view-lens-signal.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The display view's expected signal with a lens field mapping (`lens.projection`, `lens.distortion`), `lens.vignetting` or\n * camera rotation (#563), in focus and with `lens.defocus` out of focus. Loaded on demand (a dynamic import in `runCapture`),\n * so a display view without these options, and a bundle that never asks for them, does not load it.\n *\n * What it computes. The capture's environment chain forms, for site (i, j) of CFA channel c,\n * μ_c(i, j) = Σ_o w_o · (1/T) Σ_t Σ_λ A_c(λ) Σ_k K_λ(k) · F(s) · L(D_t(s), λ), s = q_o(i, j) − k·p,\n * with q_o the query point of offset o (pixel-aperture node minus anti-aliasing split), K_λ the site kernel (diffraction, the\n * defocus disc or both; a single unit tap without them), D_t the scene ray of sensor point s at temporal midpoint t (inverse\n * distortion, the declared projection, the camera rotation at t), F = T·A its field factor (vignetting throughput × distortion\n * area factor) and A_c(λ) the electrons per unit spectral radiance on the axis (the display view's channel response, ideal\n * optics). In focus with a kernel this is the environment PSF quadrature (the field factor applied once at the source point,\n * before the PSF spreads the light); out of focus it is #548's image-space disc, the same sum in another order\n * (`defocus-image-space-provider.ts`); without a kernel it is the environment's own per-query sum. Only the scene access changes:\n * the readout, the estimators, the demosaic and the development run unchanged on these site values.\n *\n * Scene points. Without a kernel each query point is formed with the environment's own arithmetic (the site centre, aperture node\n * and split offset of `native-environment-lean.ts`), then `lookOf` (the environment's mapping, rotation and field factor,\n * #548) and the planar provider's plane-point arithmetic, so a point exactly on a chart boundary resolves as in the capture.\n * With a kernel the sources are the site lattice of each fractional offset, with #548's lattice formula. Kernels, materials and\n * per-material sums are the display view's own tables (`displayViewSignalTables`), shared with the rectilinear path.\n *\n * Caches (memory only, never values): site values in a ring of native rows across windows, and with a kernel each lattice\n * point's material (or radiance at each node) and field factor per lattice group and temporal midpoint, in a two-dimensional\n * ring tagged with the point, sized from the window and capped at LATTICE_CACHE_LIMIT entries (beyond it, points are\n * evaluated as they are read).\n *\n * Large defocus kernels (#564, `input.largeKernel`, radius above 64 sites). The image-space disc D is the same at every lattice\n * group, spectral node and temporal midpoint, so it commutes with those sums as in the rectilinear signal (`expected-signal.ts`):\n * μ_c(x) = Σ_s D(s)·E_c(x − s), with E_c(x) the sum above through the in-focus kernels (each node's diffraction kernel, or a unit\n * tap) at site position x for channel c, whatever x's own channel. E is computed in fixed 64-site tiles (all three channels, each\n * group's lattice points mapped once per tile and midpoint), and D ⊛ E_c by runs (`site-kernel-runs.ts`) in fixed 128-site tiles,\n * each site taking its own channel: every value depends only on its site, so regions and parts equal the whole view.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { createSiteKernelRunsLattice, type SiteKernelRunsRowPattern } from \"../optics/site-kernel-runs.js\";\nimport type { PreparedDefocusImageSpaceGeometry } from \"./defocus-image-space-provider.js\";\nimport { displayViewSignalTables, type DisplayViewExpectedSignal, type DisplayViewExpectedSignalInput } from \"./expected-signal.js\";\n\n/** What the lens signal needs from the resolved request. */\nexport interface DisplayViewLensSetup {\n geometry: PreparedDefocusImageSpaceGeometry;\n /** Temporal midpoints, seconds from exposure start: (i + 0.5)·shutter/T with camera rotation, [0] without. */\n times: readonly number[];\n /** The planar provider's plane distance and frame-unit scale. */\n distanceM: number;\n metresPerFrameUnit: number;\n pitch: number;\n imagingArea: { widthMm: number; heightMm: number };\n boxSamples: number;\n /** Anti-aliasing split spots (or one zero spot), in the order of the expected signal's offsets within each aperture node. */\n spots: readonly { offsetMicrometers: { x: number; y: number } }[];\n}\n\n/** Largest lattice cache, in entries over all lattice groups and temporal midpoints (times the spectral nodes for radiance scenes). */\nconst LATTICE_CACHE_LIMIT = 1 << 22;\n\nconst pow2 = (n: number): number => { let p = 1; while (p < n) p *= 2; return p; };\n\n/**\n * Checks that the mapping and the vignetting profile cover the farthest source point the view reads, (W/2 + reachSites, H/2 + reachSites)\n * sites from the axis at each corner (reachSites: the kernel radius plus the largest query offset, less the half site to the outer site\n * centre), and returns the factory of the view's expected signal for this request.\n */\nexport function prepareDisplayViewLensSignal(lens: DisplayViewLensSetup, nativeWidth: number, nativeHeight: number, reachSites: number, options: string):\n (input: DisplayViewExpectedSignalInput, spanColumns?: number) => DisplayViewExpectedSignal {\n const xMm = (nativeWidth / 2 + reachSites) * lens.pitch / 1000, yMm = (nativeHeight / 2 + reachSites) * lens.pitch / 1000;\n for (const t of lens.times) for (const [x, y] of [[-xMm, -yMm], [xMm, -yMm], [-xMm, yMm], [xMm, yMm]] as const) {\n try { if (!(lens.geometry.lookOf(x, y, t).z > 0)) throw new InvalidConfigurationError(\"its ray does not point toward the scene plane.\"); } catch (error) {\n throw new InvalidConfigurationError(\"simulateDisplayView with \" + options + \" reads the scene through the lens up to \" + (reachSites + 0.5) + \" sites beyond the native \" +\n \"raster's outer site centres (the kernel radius and the query offsets), and there (\" + Math.hypot(x, y).toFixed(3) + \" mm from the axis) \" + (error as Error).message);\n }\n }\n return (input, spanColumns = Infinity) => createLensSignal(lens, input, spanColumns);\n}\n\nfunction createLensSignal(lens: DisplayViewLensSetup, input: DisplayViewExpectedSignalInput, spanColumns: number): DisplayViewExpectedSignal {\n const W = input.nativeWidth, H = input.nativeHeight, nodes = input.wavelengthsNm.length, T = lens.times.length, times = lens.times;\n const { geometry, distanceM: distance, metresPerFrameUnit: scale, pitch, imagingArea } = lens;\n const mmPerSite = pitch / 1000, scene = input.scene, offsets = input.offsets, A = input.electronsPerRadiance, channelAt = input.channelAt;\n const materials = scene.kind === \"materials\" ? scene : undefined, radianceAt = scene.kind === \"radiance\" ? scene.radianceAt : undefined;\n const { reflectance, spectralIndex, neutralDirect, spectralDirect, groups } = displayViewSignalTables(input);\n const kernels = input.kernels, R = kernels ? kernels.radius : 0;\n let lookups = 0;\n // The plane point (frame units) and field factor of native sensor point (x, y) mm at time t: the environment's mapping (lookOf) and\n // the planar provider's own arithmetic for the outgoing direction −look.\n let pu = 0, pv = 0, pf = 0;\n const map = (xMm: number, yMm: number, t: number): void => {\n const look = geometry.lookOf(xMm, yMm, t);\n if (!(look.z > 0)) throw new InvalidConfigurationError(\"simulateDisplayView: a query ray does not point toward the scene plane.\");\n const s = distance / look.z;\n pu = look.x * s / scale; pv = look.y * s / scale; pf = look.factor;\n };\n const materialOf = (m: number): number => { if (spectralIndex[m] === undefined) throw new InvalidConfigurationError(\"Unknown chart material.\"); return m; };\n // Without a kernel: the environment's query point of offset o of site (x, y) (native-environment-lean.ts, as buildExpectedSignalInput's queryPoint).\n const box = lens.boxSamples, siteWidthMm = pitch / 1000;\n const phases = offsets.map((_, o) => {\n const node = Math.floor(o / lens.spots.length), spot = lens.spots[o % lens.spots.length]!.offsetMicrometers;\n return { xPhase: (node % box + 0.5) / box, yPhase: (Math.floor(node / box) + 0.5) / box, aaX: spot.x / 1000, aaY: spot.y / 1000 };\n });\n function directSite(x: number, y: number): number {\n const c = channelAt(x, y), centerX = -imagingArea.widthMm / 2 + (pitch / 2 + x * pitch + 0) / 1000, centerY = -imagingArea.heightMm / 2 + (pitch / 2 + y * pitch + 0) / 1000;\n let total = 0;\n for (let ti = 0; ti < T; ti++) {\n let sum = 0;\n for (let o = 0; o < offsets.length; o++) {\n const node = phases[o]!;\n map((centerX - siteWidthMm / 2 + node.xPhase * siteWidthMm) - node.aaX, (centerY - siteWidthMm / 2 + node.yPhase * siteWidthMm) - node.aaY, times[ti]!);\n let value: number;\n if (materials) {\n const m = materialOf(materials.materialAt(pu, pv)), si = spectralIndex[m]!;\n value = si < 0 ? reflectance[m]! * neutralDirect[c]! : spectralDirect[c]![si]!; lookups++;\n } else { value = 0; for (let n = 0; n < nodes; n++) value += A[c]![n]! * radianceAt!(pu, pv, input.wavelengthsNm[n]!); lookups += nodes; }\n sum += offsets[o]!.weight * (pf * value);\n }\n total += sum;\n }\n return total / T;\n }\n // With a kernel: lattice point (p, q) of group g at time t, #548's lattice formula, cached in a ring tagged with (p, q).\n const G = groups.length, slots = G * T, per = materials ? 1 : nodes;\n let cacheRows = 0, cacheCols = 0, tagQ = new Int32Array(0), tagP = new Int32Array(0), cacheMaterial = new Int32Array(0), cacheFactor = new Float64Array(0), cacheRadiance = new Float64Array(0);\n const radiance = new Float64Array(nodes);\n let lm = 0, lf = 0;\n function lattice(g: number, ti: number, p: number, q: number): void {\n let k = -1;\n if (cacheRows > 0) {\n k = ((g * T + ti) * cacheRows + (q & (cacheRows - 1))) * cacheCols + (p & (cacheCols - 1));\n if (tagQ[k] === q && tagP[k] === p) {\n lf = cacheFactor[k]!;\n if (materials) lm = cacheMaterial[k]!; else for (let n = 0; n < nodes; n++) radiance[n] = cacheRadiance[k * nodes + n]!;\n return;\n }\n }\n const group = groups[g]!;\n map((p + 0.5 + group.fx - W / 2) * mmPerSite, (q + 0.5 + group.fy - H / 2) * mmPerSite, times[ti]!);\n lf = pf;\n if (materials) { lm = materialOf(materials.materialAt(pu, pv)); lookups++; }\n else { for (let n = 0; n < nodes; n++) radiance[n] = radianceAt!(pu, pv, input.wavelengthsNm[n]!); lookups += nodes; }\n if (k >= 0) {\n tagQ[k] = q; tagP[k] = p; cacheFactor[k] = lf;\n if (materials) cacheMaterial[k] = lm; else for (let n = 0; n < nodes; n++) cacheRadiance[k * nodes + n] = radiance[n]!;\n }\n }\n function kernelSite(x: number, y: number): number {\n const c = channelAt(x, y), rowMask = cacheRows - 1, colMask = cacheCols - 1;\n let total = 0;\n for (let ti = 0; ti < T; ti++) {\n let sum = 0;\n for (let g = 0; g < G; g++) {\n const group = groups[g]!, p0 = x + group.minIx - R, q0 = y + group.minIy - R, cw = group.cw, ch = group.ch;\n if (materials) {\n const nk = group.neutral[c]!, sk = group.spectral[c]!;\n for (let dy = 0, t = 0; dy < ch; dy++) {\n // The cache row of lattice row q (read inline: the common case is a hit).\n const q = q0 + dy, row = cacheRows > 0 ? ((g * T + ti) * cacheRows + (q & rowMask)) * cacheCols : -1;\n for (let dx = 0; dx < cw; dx++, t++) {\n const p = p0 + dx, k = row + (p & colMask);\n if (row >= 0 && tagQ[k] === q && tagP[k] === p) { lm = cacheMaterial[k]!; lf = cacheFactor[k]!; } else lattice(g, ti, p, q);\n const si = spectralIndex[lm]!;\n sum += lf * (si < 0 ? reflectance[lm]! * nk[t]! : sk[si]![t]!);\n }\n }\n } else for (let dy = 0, t = 0; dy < ch; dy++) for (let dx = 0; dx < cw; dx++, t++) {\n lattice(g, ti, p0 + dx, q0 + dy);\n let value = 0;\n for (let n = 0; n < nodes; n++) value += group.perNode[n]![c]![t]! * radiance[n]!;\n sum += lf * value;\n }\n }\n total += sum;\n }\n return total / T;\n }\n const pilotNode = input.wavelengthsNm[Math.floor(nodes / 2)]!;\n if (input.largeKernel) return createLargeLensSignal(input, inFocusLensTile, () => lookups, pilot);\n /** E_c (#564) of the native site positions [x0, x0 + T) × [y0, y0 + T) for the three channels: kernelSite's sum for each channel. */\n function inFocusLensTile(x0: number, y0: number, TS: number): Float64Array[] {\n const out = [0, 1, 2].map(() => new Float64Array(TS * TS));\n // A fixed tile reaches past the raster: positions more than the disc's radius beyond it feed no site, so they stay 0 and are never\n // mapped (the lens profiles are checked only up to the view's reach).\n const D = input.largeKernel!.radius;\n if (x0 + TS <= -D || x0 >= W + D || y0 + TS <= -D || y0 >= H + D) return out;\n if (x0 < -D || x0 + TS > W + D || y0 < -D || y0 + TS > H + D) {\n const xa = Math.max(x0, -D), xb = Math.min(x0 + TS, W + D), ya = Math.max(y0, -D), yb = Math.min(y0 + TS, H + D);\n const part = inFocusLensRect(xa, ya, xb - xa, yb - ya);\n for (let c = 0; c < 3; c++) for (let y = ya; y < yb; y++) out[c]!.set(part[c]!.subarray((y - ya) * (xb - xa), (y - ya + 1) * (xb - xa)), (y - y0) * TS + xa - x0);\n return out;\n }\n return inFocusLensRect(x0, y0, TS, TS);\n }\n /** E_c of the native site positions [x0, x0 + w) × [y0, y0 + h), row-major, for the three channels. */\n function inFocusLensRect(x0: number, y0: number, TW: number, TH: number): Float64Array[] {\n const out = [0, 1, 2].map(() => new Float64Array(TW * TH)), sum = [0, 1, 2].map(() => new Float64Array(TW * TH));\n for (let ti = 0; ti < T; ti++) {\n for (const e of sum) e.fill(0);\n for (const group of groups) {\n const cw = group.cw, ch = group.ch, gw = TW + cw - 1, gh = TH + ch - 1, p0 = x0 + group.minIx - R, q0 = y0 + group.minIy - R;\n const factor = new Float64Array(gw * gh), material = materials ? new Int32Array(gw * gh) : undefined, values = materials ? undefined : new Float64Array(gw * gh * nodes);\n for (let j = 0; j < gh; j++) for (let i = 0; i < gw; i++) {\n const k = j * gw + i;\n map((p0 + i + 0.5 + group.fx - W / 2) * mmPerSite, (q0 + j + 0.5 + group.fy - H / 2) * mmPerSite, times[ti]!);\n factor[k] = pf;\n if (material) material[k] = materialOf(materials!.materialAt(pu, pv));\n else for (let n = 0; n < nodes; n++) values![k * nodes + n] = radianceAt!(pu, pv, input.wavelengthsNm[n]!);\n }\n lookups += material ? gw * gh : gw * gh * nodes;\n for (let c = 0; c < 3; c++) {\n const e = sum[c]!, nk = group.neutral[c], sk = group.spectral[c];\n for (let y = 0; y < TH; y++) for (let x = 0; x < TW; x++) {\n let v = 0;\n for (let dy = 0, t = 0; dy < ch; dy++) for (let dx = 0; dx < cw; dx++, t++) {\n const k = (y + dy) * gw + x + dx;\n if (material) { const m = material[k]!, si = spectralIndex[m]!; v += factor[k]! * (si < 0 ? reflectance[m]! * nk![t]! : sk![si]![t]!); }\n else { let r = 0; for (let n = 0; n < nodes; n++) r += group.perNode[n]![c]![t]! * values![k * nodes + n]!; v += factor[k]! * r; }\n }\n e[y * TW + x] = e[y * TW + x]! + v;\n }\n }\n }\n for (let c = 0; c < 3; c++) { const o = out[c]!, e = sum[c]!; for (let k = 0; k < o.length; k++) o[k] = o[k]! + e[k]!; }\n }\n for (const o of out) for (let k = 0; k < o.length; k++) o[k] = o[k]! / T;\n return out;\n }\n // Site values persist across windows in a ring of native rows (a site's value does not depend on the window).\n let ringRows = 0, ring = new Float64Array(0), ringRowId = new Int32Array(0), ringOn = false;\n const compute = kernels ? kernelSite : directSite;\n return {\n get lookups(): number { return lookups; },\n uniformMaterial: -1,\n tracksMaterial: false,\n get cachesSites(): boolean { return ringOn; },\n marksReads: false,\n markReads(): void { /* never called: marksReads is false */ },\n window(x0: number, y0: number, x1: number, y1: number): void {\n const sw = Math.max(0, x1 - x0), sh = Math.max(0, y1 - y0);\n if (sh > 0 && ringRows < 2 * sh) {\n const rows = pow2(2 * sh);\n if (rows * W <= LATTICE_CACHE_LIMIT) { ringRows = rows; ring = new Float64Array(rows * W).fill(NaN); ringRowId = new Int32Array(rows).fill(-1); }\n }\n ringOn = sh > 0 && ringRows >= 2 * sh;\n if (!kernels || sw === 0) return;\n // The lattice rectangle the window's sites read, per group; the cache keeps two such heights and the columns the render's windows span.\n let cw = 0, ch = 0;\n for (const group of groups) { cw = Math.max(cw, group.cw); ch = Math.max(ch, group.ch); }\n const height = sh + ch - 1, width = sw + cw - 1;\n let rows = pow2(2 * height), cols = pow2(Math.min(W + 2 * (R + cw), Math.max(width, (Number.isFinite(spanColumns) ? spanColumns : W) + width)));\n if (slots * per * rows * cols > LATTICE_CACHE_LIMIT) rows = pow2(height);\n if (slots * per * rows * cols > LATTICE_CACHE_LIMIT) cols = pow2(width);\n if (slots * per * rows * cols > LATTICE_CACHE_LIMIT) { cacheRows = 0; return; }\n if (rows > cacheRows || cols > cacheCols) {\n rows = Math.max(rows, cacheRows); cols = Math.max(cols, cacheCols);\n if (slots * per * rows * cols > LATTICE_CACHE_LIMIT) { rows = pow2(height); cols = pow2(width); }\n cacheRows = rows; cacheCols = cols;\n const size = slots * rows * cols;\n tagQ = new Int32Array(size).fill(-2147483648); tagP = new Int32Array(size); cacheFactor = new Float64Array(size);\n if (materials) cacheMaterial = new Int32Array(size); else cacheRadiance = new Float64Array(size * nodes);\n }\n },\n site(x: number, y: number): number {\n if (!ringOn) return compute(x, y);\n const slot = y & (ringRows - 1), k = slot * W + x;\n if (ringRowId[slot] === y) { const v = ring[k]!; if (v === v) return v; }\n else { ringRowId[slot] = y; ring.fill(NaN, slot * W, (slot + 1) * W); }\n const v = compute(x, y);\n ring[k] = v;\n return v;\n },\n pilot\n };\n /**\n * The renderer's pilot point is a rectilinear plane point of the native raster: back to the sensor point, then through the lens at\n * every temporal midpoint. A point whose scene value differs between the instants (motion) counts as detail (NaN equals nothing).\n */\n function pilot(u: number, v: number): number {\n const g = 2 / input.outputWidth, xMm = u / g * mmPerSite, yMm = -v / g * mmPerSite;\n let first = NaN;\n try {\n for (let ti = 0; ti < T; ti++) {\n map(xMm, yMm, times[ti]!);\n const value = materials ? materials.materialAt(pu, pv) : radianceAt!(pu, pv, pilotNode);\n lookups++;\n if (ti === 0) first = value; else if (value !== first) return NaN;\n }\n } catch { return NaN; }\n return first;\n }\n}\n\n/** #564: tile sides of the large-kernel lens signal (the in-focus E and the convolved sites) and the bytes each tile cache keeps. */\nconst LARGE_E_TILE = 64, LARGE_OUTPUT_TILE = 128, LARGE_CACHE_BYTES = 32 * 1048576;\n\n/** #564: the lens signal with a defocus kernel above 64 sites: D ⊛ E_c by runs over the in-focus tiles (see the module comment). */\nfunction createLargeLensSignal(input: DisplayViewExpectedSignalInput, inFocusTile: (x0: number, y0: number, T: number) => Float64Array[], lookups: () => number,\n pilot: (u: number, v: number) => number): DisplayViewExpectedSignal {\n const runs = input.largeKernel!, channelAt = input.channelAt, TE = LARGE_E_TILE;\n // At least the in-focus tiles one output tile's source spans plus one more row of them, so the next output tile of a row reuses them.\n const span = Math.ceil((LARGE_OUTPUT_TILE + 2 * runs.radius) / TE) + 1;\n const inFocus = new Map<number, Float64Array[]>(), capacity = Math.max(span * (span + 1), Math.floor(LARGE_CACHE_BYTES / (3 * TE * TE * 8)));\n const tileAt = (tx: number, ty: number): Float64Array[] => {\n const key = (ty + 1048576) * 2097152 + tx + 1048576;\n let tile = inFocus.get(key);\n if (tile) { inFocus.delete(key); inFocus.set(key, tile); }\n else {\n tile = inFocusTile(tx * TE, ty * TE, TE);\n inFocus.set(key, tile);\n if (inFocus.size > capacity) inFocus.delete(inFocus.keys().next().value!);\n }\n return tile;\n };\n // Which sites of a tile row hold channel c: the CFA's 2 × 2 period (tile origins are even).\n const phase = [0, 1].map((py) => [0, 1].map((px) => channelAt(px, py)));\n const patterns: SiteKernelRunsRowPattern[] = [0, 1, 2].map((c) => (row: number) => {\n const p = phase[row & 1]!, even = p[0] === c, odd = p[1] === c;\n return even && odd ? { start: 0, step: 1 } : even ? { start: 0, step: 2 } : odd ? { start: 1, step: 2 } : null;\n });\n const lattice = createSiteKernelRunsLattice({ runs, tile: LARGE_OUTPUT_TILE, fields: 3, capacityBytes: LARGE_CACHE_BYTES, pattern: (c) => patterns[c],\n source: (x0, y0, width, height) => (c: number): Float64Array => {\n const samples = new Float64Array(width * height);\n for (let ty = Math.floor(y0 / TE); ty * TE < y0 + height; ty++) for (let tx = Math.floor(x0 / TE); tx * TE < x0 + width; tx++) {\n const tile = tileAt(tx, ty)[c]!, ax = Math.max(x0, tx * TE), bx = Math.min(x0 + width, (tx + 1) * TE), ay = Math.max(y0, ty * TE), by = Math.min(y0 + height, (ty + 1) * TE);\n for (let y = ay; y < by; y++) samples.set(tile.subarray((y - ty * TE) * TE + ax - tx * TE, (y - ty * TE) * TE + bx - tx * TE), (y - y0) * width + ax - x0);\n }\n return samples;\n } });\n return {\n get lookups(): number { return lookups(); },\n uniformMaterial: -1,\n tracksMaterial: false,\n cachesSites: false,\n marksReads: false,\n markReads(): void { /* never called: marksReads is false */ },\n window(): void { /* the tiles are fixed and kept for the signal; a window changes nothing */ },\n site(x: number, y: number): number { return lattice.valueAt(channelAt(x, y), x, y); },\n pilot\n };\n}\n"]}
@@ -129,6 +129,16 @@ export interface DisplayViewRenderResult {
129
129
  * overlap weight (views where a footprint holds at most K² real pixels); "stratified-monte-carlo" otherwise.
130
130
  */
131
131
  estimation: "exact-area-mean" | "stratified-monte-carlo";
132
+ /**
133
+ * #533: per display pixel (region row-major), the expected number of the real capture's output pixels in its rectangle that
134
+ * have at least one clipped contributing site (`simulateCapture`'s `diagnostics.highlight.saturatedPixelCount`, counted on
135
+ * the capture's one noise sample): Σ_j w_j·P_j, w_j the area of real pixel j inside the rectangle and P_j the probability,
136
+ * under the view's site model, that a site j's demosaic reads is at or above the white level. Estimated as the expected value
137
+ * is (exact area mean or stratified Monte Carlo); it never changes a sample.
138
+ */
139
+ saturated: Float64Array;
140
+ /** #533: Σ of `saturated` in region row-major order: the region's expected saturated-pixel count (additive over regions). */
141
+ saturatedPixelCount: number;
132
142
  }
133
143
  /** One tap of a linear demosaic kernel: the site at (dx, dy) from the pixel, and its weight. */
134
144
  export interface DisplayViewKernelTap {
@@ -149,6 +159,17 @@ export declare function overlaps(start: number, end: number, limit: number): {
149
159
  first: number;
150
160
  w: Float64Array;
151
161
  };
162
+ /**
163
+ * Internal (#533, the GPU renderers' host): the saturated-pixel share `renderDisplayView` gives a display pixel on the exact path
164
+ * when every real pixel's saturation probability is exactly 0 or 1: bit j·nx + i of the 36-bit mask (`low` bits 0–31, `high` bits
165
+ * 32–35) is 1 for P = 1, nx the columns' overlap count. The arithmetic is the render's own (Σ_j a_j·P_j in its order, a_j = w_x·w_y / A,
166
+ * then times A), so the value has the reference's bits.
167
+ */
168
+ export declare function displayViewDecidedSaturation(columns: {
169
+ w: Float64Array;
170
+ }, rows: {
171
+ w: Float64Array;
172
+ }, area: number, low: number, high: number): number;
152
173
  /**
153
174
  * Internal (exported for tests). Footprint sums along one axis, for the closed-form B_c (docs/DISPLAY_VIEW.md, "Demosaic correlation"). Native
154
175
  * coordinate parity decides the CFA: red columns/rows are even, blue odd. With w(k) the overlap of real column k:
@@ -226,6 +226,22 @@ export function overlaps(start, end, limit) {
226
226
  w[k - first] = Math.min(end, k + 1) - Math.max(start, k);
227
227
  return { first, w };
228
228
  }
229
+ /**
230
+ * Internal (#533, the GPU renderers' host): the saturated-pixel share `renderDisplayView` gives a display pixel on the exact path
231
+ * when every real pixel's saturation probability is exactly 0 or 1: bit j·nx + i of the 36-bit mask (`low` bits 0–31, `high` bits
232
+ * 32–35) is 1 for P = 1, nx the columns' overlap count. The arithmetic is the render's own (Σ_j a_j·P_j in its order, a_j = w_x·w_y / A,
233
+ * then times A), so the value has the reference's bits.
234
+ */
235
+ export function displayViewDecidedSaturation(columns, rows, area, low, high) {
236
+ const nx = columns.w.length;
237
+ let sat = 0;
238
+ for (let j = 0; j < rows.w.length; j++)
239
+ for (let i = 0; i < nx; i++) {
240
+ const bit = j * nx + i, set = bit < 32 ? (low >>> bit) & 1 : (high >>> (bit - 32)) & 1;
241
+ sat += columns.w[i] * rows.w[j] / area * (set === 1 ? 1 : 0);
242
+ }
243
+ return (sat / 1) * area;
244
+ }
229
245
  export function axisSums(start, end, limit, margin) {
230
246
  const { first, w } = overlaps(start, end, limit);
231
247
  const at = (k) => (k >= first && k < first + w.length ? w[k - first] : 0);
@@ -482,9 +498,10 @@ function correctionStates(key) {
482
498
  /**
483
499
  * Recorded terms of a one-material sample: [0, 3) the channel site variances csv; [3, 21) per candidate d and channel c the
484
500
  * linear slopes a (3 + (3d + c)·3); [21, 27) per candidate the residual terms; [27, 30) the expected-value sums; [30, 33) the
485
- * AHD choice terms; 33 a 1 when the AHD correction applies and [34, 37) its values.
501
+ * AHD choice terms; 33 a 1 when the AHD correction applies and [34, 37) its values; 37 the real pixel's saturation probability
502
+ * (#533: the probability that at least one site its demosaic reads is clipped at the white level).
486
503
  */
487
- const MEMO_SIZE = 37;
504
+ const MEMO_SIZE = 38;
488
505
  /** Most real pixels a display pixel's footprint may have for the per-real-pixel memo (#392); larger footprints rarely repeat a real pixel. */
489
506
  const PIXEL_MEMO_LIMIT = 1 << 16;
490
507
  /**
@@ -793,7 +810,8 @@ export async function renderDisplayView(setup) {
793
810
  const maximum = setup.bitDepth === 8 ? 255 : 65535, step = 1 / maximum;
794
811
  const pixelCount = region.width * region.height;
795
812
  const samples = setup.bitDepth === 8 ? new Uint8Array(pixelCount * 3) : new Uint16Array(pixelCount * 3);
796
- const expected = new Float64Array(pixelCount * 3), noiseStd = new Float64Array(pixelCount * 3);
813
+ const expected = new Float64Array(pixelCount * 3), noiseStd = new Float64Array(pixelCount * 3), saturated = new Float64Array(pixelCount);
814
+ let saturatedTotal = 0;
797
815
  const columns = Array.from({ length: region.width }, (_, i) => axisSums((region.x + i) * sx, (region.x + i + 1) * sx, frameWidth, margin));
798
816
  const M = setup.matrix, m00 = M[0][0], m01 = M[0][1], m02 = M[0][2], m10 = M[1][0], m11 = M[1][1], m12 = M[1][2], m20 = M[2][0], m21 = M[2][1], m22 = M[2][2];
799
817
  const g0 = setup.gains[0], g1 = setup.gains[1], g2 = setup.gains[2], L = setup.clipLevel, reinhard = setup.toneCurve === "positive-reinhard-per-channel";
@@ -804,6 +822,8 @@ export async function renderDisplayView(setup) {
804
822
  const reach = Math.max(1, ...candidates.flat(3).map((t) => Math.max(Math.abs(t.dx), Math.abs(t.dy)))), side = 2 * reach + 1, slotsCount = side * side;
805
823
  const slotOf = (t) => (t.dy + reach) * side + t.dx + reach;
806
824
  const { dx: slotDx, dy: slotDy } = displayViewSlotOffsets(reach);
825
+ /** The raster index of native site (x, y) read reflect-101, as the sample loop reads it. */
826
+ const reflectedSite = (x, y) => (y < 0 ? -y : y >= nativeHeight ? 2 * nativeHeight - 2 - y : y) * nativeWidth + (x < 0 ? -x : x >= nativeWidth ? 2 * nativeWidth - 2 - x : x);
807
827
  // Per phase: the bilinear kernels (for the site variance of each channel), the candidates, and the slots they read.
808
828
  const phaseSlots = [], phaseWeights = [], phaseW2 = [], phaseList = [];
809
829
  const candidateSlots = [], candidateWeights = [], candidateDense = [], candidateList = [];
@@ -826,7 +846,7 @@ export async function renderDisplayView(setup) {
826
846
  }
827
847
  // The same tables flat (phase·2 + candidate, ·3 + channel), read by the sample loop below.
828
848
  const { count: candidateCount, denseAt, listAt, slotsAt, weightsAt } = flatDisplayViewCandidateTables(candidateSlots, candidateWeights, candidateDense, candidateList);
829
- const siteElectrons = new Float64Array(slotsCount), siteMean = new Float64Array(slotsCount), siteVar = new Float64Array(slotsCount), siteThird = new Float64Array(slotsCount), siteChannel = new Int32Array(slotsCount), clip = new Float64Array(3), B = new Float64Array(4), C = new Float64Array(9);
849
+ const siteElectrons = new Float64Array(slotsCount), siteClip = new Float64Array(slotsCount), siteMean = new Float64Array(slotsCount), siteVar = new Float64Array(slotsCount), siteThird = new Float64Array(slotsCount), siteChannel = new Int32Array(slotsCount), clip = new Float64Array(3), B = new Float64Array(4), C = new Float64Array(9);
830
850
  const cm = new Float64Array(3), cv = new Float64Array(3), csv = new Float64Array(3), bm = new Float64Array(3), bv = new Float64Array(3), bs = new Float64Array(3);
831
851
  const hm = new Float64Array(3), hv = new Float64Array(3), hs = new Float64Array(3), an = new Float64Array(9);
832
852
  const reach2 = CLIP_REACH_SIGMA * CLIP_REACH_SIGMA;
@@ -847,7 +867,7 @@ export async function renderDisplayView(setup) {
847
867
  const siteMask = siteRows - 1, ringCapacity = siteRows * siteW, ringUsable = exactView && ringCapacity <= SITE_RING_LIMIT;
848
868
  // Allocated at the first display pixel that uses the ring (a render whose windows never fill allocates nothing).
849
869
  let ringStamp = new Int32Array(0), ringStatStamp = ringStamp, ringMat = ringStamp, siteSlotQ = ringStamp, siteSlotStamp = ringStamp, markX = ringStamp, markY = ringStamp, markM = ringStamp;
850
- let ringV = new Float64Array(0), ringMean = ringV, ringVar = ringV, ringThird = ringV, markV = ringV;
870
+ let ringV = new Float64Array(0), ringMean = ringV, ringVar = ringV, ringThird = ringV, ringClip = ringV, markV = ringV;
851
871
  // (No closure assigns them, so they stay locals of the render loop.)
852
872
  // AHD low-signal correction: an 11 × 11 noisy neighbourhood (AHD reads up to 5 sites away) and the local AHD steps.
853
873
  const ahdCorrection = setup.ahdCorrection, windowReach = ahdCorrection ? Math.max(reach, AHD_REACH) : reach;
@@ -911,14 +931,17 @@ export async function renderDisplayView(setup) {
911
931
  const c = siteChannel[slot], e = siteElectrons[slot], kc = k[c], mean = kc * e, variance = kc * kc * e + c0[c], gap = 1 - mean;
912
932
  // Third cumulant of the normalized value: Poisson electrons have κ₃ = e (read and rounding noise add none).
913
933
  siteThird[slot] = kc * kc * kc * e;
934
+ // #533: the clip probability P(value ≥ 1) is 1 − P(value < 1), the clip's own slope (0 where the clip is out of reach).
914
935
  if (gap > 0 && gap * gap > reach2 * variance) {
915
936
  siteMean[slot] = mean;
916
937
  siteVar[slot] = variance;
938
+ siteClip[slot] = 0;
917
939
  }
918
940
  else {
919
941
  upperClip(mean, variance, 1, clip);
920
942
  siteMean[slot] = clip[0];
921
943
  siteVar[slot] = clip[1];
944
+ siteClip[slot] = 1 - clip[2];
922
945
  }
923
946
  }
924
947
  let siteCount = 0, sampleCount = 0, detail = 0, uniform = 0, lastYield = Date.now();
@@ -1003,6 +1026,7 @@ export async function renderDisplayView(setup) {
1003
1026
  ringMean = new Float64Array(ringCapacity);
1004
1027
  ringVar = new Float64Array(ringCapacity);
1005
1028
  ringThird = new Float64Array(ringCapacity);
1029
+ ringClip = new Float64Array(ringCapacity);
1006
1030
  siteSlotQ = new Int32Array(slotsCount);
1007
1031
  siteSlotStamp = new Int32Array(slotsCount);
1008
1032
  markX = new Int32Array(slotsCount);
@@ -1023,7 +1047,7 @@ export async function renderDisplayView(setup) {
1023
1047
  }
1024
1048
  pixelGeneration++;
1025
1049
  }
1026
- let s0 = 0, s1 = 0, s2 = 0, c00 = 0, c01 = 0, c02 = 0, c11 = 0, c12 = 0, c22 = 0, r0 = 0, r1 = 0, r2 = 0, pixelVariance = 0, corrected = false;
1050
+ let s0 = 0, s1 = 0, s2 = 0, c00 = 0, c01 = 0, c02 = 0, c11 = 0, c12 = 0, c22 = 0, r0 = 0, r1 = 0, r2 = 0, pixelVariance = 0, corrected = false, sat = 0;
1027
1051
  for (let n = 0; n < sampleTotal; n++) {
1028
1052
  // A sample's weights: 1 for the stratified estimator (its sums are divided by Q below); a_j for the expected value and
1029
1053
  // linear covariance and a_j² for the independent residual on the exact path. Multiplying by 1 leaves every value's bits.
@@ -1113,28 +1137,33 @@ export async function renderDisplayView(setup) {
1113
1137
  siteMean[slot] = ringMean[q];
1114
1138
  siteVar[slot] = ringVar[q];
1115
1139
  siteThird[slot] = ringThird[q];
1140
+ siteClip[slot] = ringClip[q];
1116
1141
  continue;
1117
1142
  }
1118
1143
  // As siteStatistics, written out here for the untracked (Speed) path.
1119
1144
  const kc = k[c], mean = kc * e, variance = kc * kc * e + c0[c], gap = 1 - mean, third = kc * kc * kc * e;
1120
- let sm, sv;
1145
+ let sm, sv, sp;
1121
1146
  if (gap > 0 && gap * gap > reach2 * variance) {
1122
1147
  sm = mean;
1123
1148
  sv = variance;
1149
+ sp = 0;
1124
1150
  }
1125
1151
  else {
1126
1152
  upperClip(mean, variance, 1, clip);
1127
1153
  sm = clip[0];
1128
1154
  sv = clip[1];
1155
+ sp = 1 - clip[2];
1129
1156
  }
1130
1157
  siteMean[slot] = sm;
1131
1158
  siteVar[slot] = sv;
1132
1159
  siteThird[slot] = third;
1160
+ siteClip[slot] = sp;
1133
1161
  if (q >= 0) {
1134
1162
  ringStatStamp[q] = rowStamp;
1135
1163
  ringMean[q] = sm;
1136
1164
  ringVar[q] = sv;
1137
1165
  ringThird[q] = third;
1166
+ ringClip[q] = sp;
1138
1167
  }
1139
1168
  }
1140
1169
  if (marks > 0)
@@ -1176,11 +1205,13 @@ export async function renderDisplayView(setup) {
1176
1205
  if (gap > 0 && gap * gap > reach2 * variance) {
1177
1206
  siteMean[slot] = mean;
1178
1207
  siteVar[slot] = variance;
1208
+ siteClip[slot] = 0;
1179
1209
  }
1180
1210
  else {
1181
1211
  upperClip(mean, variance, 1, clip);
1182
1212
  siteMean[slot] = clip[0];
1183
1213
  siteVar[slot] = clip[1];
1214
+ siteClip[slot] = 1 - clip[2];
1184
1215
  }
1185
1216
  }
1186
1217
  if (!tracking)
@@ -1225,6 +1256,7 @@ export async function renderDisplayView(setup) {
1225
1256
  s2 += wE * memo[mo + 36];
1226
1257
  corrected = true;
1227
1258
  }
1259
+ sat += wE * memo[mo + 37];
1228
1260
  continue;
1229
1261
  }
1230
1262
  // The terms are written where they are kept: the real pixel's memo slot, or (for the first sample of a one-material key)
@@ -1262,6 +1294,7 @@ export async function renderDisplayView(setup) {
1262
1294
  siteMean[slot] = ringMean[q];
1263
1295
  siteVar[slot] = ringVar[q];
1264
1296
  siteThird[slot] = ringThird[q];
1297
+ siteClip[slot] = ringClip[q];
1265
1298
  continue;
1266
1299
  }
1267
1300
  siteStatistics(slot);
@@ -1270,6 +1303,7 @@ export async function renderDisplayView(setup) {
1270
1303
  ringMean[q] = siteMean[slot];
1271
1304
  ringVar[q] = siteVar[slot];
1272
1305
  ringThird[q] = siteThird[slot];
1306
+ ringClip[q] = siteClip[slot];
1273
1307
  }
1274
1308
  }
1275
1309
  // Site variance of each channel through the bilinear kernels (for B_c), then the demosaic's own pixel statistics: the
@@ -1441,6 +1475,26 @@ export async function renderDisplayView(setup) {
1441
1475
  rt[ro + 28] = e1;
1442
1476
  rt[ro + 29] = e2;
1443
1477
  }
1478
+ // #533: the real pixel's saturation probability, 1 − Π_k (1 − p_k) over the distinct sites its demosaic reads (the
1479
+ // capture counts a pixel with at least one clipped contributing site; the sites' noises are independent). A site read
1480
+ // twice through the mirrored border counts once.
1481
+ let unclipped = 1;
1482
+ if (inside)
1483
+ for (let li = 0; li < list.length; li++)
1484
+ unclipped *= 1 - siteClip[list[li]];
1485
+ else
1486
+ for (let li = 0; li < list.length; li++) {
1487
+ const slot = list[li], at = reflectedSite(x + slotDx[slot], y + slotDy[slot]);
1488
+ let repeated = false;
1489
+ for (let lj = 0; lj < li && !repeated; lj++)
1490
+ repeated = reflectedSite(x + slotDx[list[lj]], y + slotDy[list[lj]]) === at;
1491
+ if (!repeated)
1492
+ unclipped *= 1 - siteClip[slot];
1493
+ }
1494
+ const saturation = 1 - unclipped;
1495
+ sat += wE * saturation;
1496
+ if (rt)
1497
+ rt[ro + 37] = saturation;
1444
1498
  if (count === 2) {
1445
1499
  // AHD's per-pixel choice between the candidates adds independent variance: with a noise-driven choice each pixel
1446
1500
  // deviates from the candidates' average by ±½(H − V), variance ¼·Var(H − V) (linear in the sites, at the last
@@ -1495,6 +1549,10 @@ export async function renderDisplayView(setup) {
1495
1549
  correctedPixels++;
1496
1550
  // Stratified: means over Q samples. Exact: the weights already sum to 1 (Σ a_j = 1) and the residual carries Σ a_j²·r_j.
1497
1551
  const Qd = exactView ? 1 : Q, mean0 = s0 / Qd, mean1 = s1 / Qd, mean2 = s2 / Qd, pixels = B[3];
1552
+ // #533: the expected saturated real pixels of the rectangle (A real pixels): A·Σ_j a_j·P_j, or A times the samples' mean.
1553
+ const saturatedHere = (sat / Qd) * area;
1554
+ saturated[ry * region.width + rx] = saturatedHere;
1555
+ saturatedTotal += saturatedHere;
1498
1556
  // The real pixels' output rounding (Δ²/12 in the encoded domain), mapped to linear light at the mean.
1499
1557
  const q0 = quantizationVariance(mean0, step), q1 = quantizationVariance(mean1, step), q2 = quantizationVariance(mean2, step);
1500
1558
  // Covariance in linear light: the linear part plus the independent per-pixel residuals and rounding.
@@ -1527,7 +1585,7 @@ export async function renderDisplayView(setup) {
1527
1585
  }
1528
1586
  }
1529
1587
  return { samples, expected, noiseStd, sampleCount, siteCount, detailPixelCount: detail, uniformPixelCount: uniform, ahdCorrectedPixelCount: correctedPixels,
1530
- estimation: exactView ? "exact-area-mean" : "stratified-monte-carlo" };
1588
+ estimation: exactView ? "exact-area-mean" : "stratified-monte-carlo", saturated, saturatedPixelCount: saturatedTotal };
1531
1589
  }
1532
1590
  /**
1533
1591
  * The centre c of a normal of variance v whose clip to [0, 1] has mean `target` (bisection; c = target when the noise does