@photivra/engine 2.15.0 → 2.16.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 (67) hide show
  1. package/CHANGELOG.md +47 -1
  2. package/CITATION.cff +1 -1
  3. package/README.md +6 -6
  4. package/SECURITY.md +1 -1
  5. package/THIRD_PARTY.md +14 -0
  6. package/dist/capture/native-environment-lean.js +1 -1
  7. package/dist/capture/native-environment-lean.js.map +1 -1
  8. package/dist/capture/native-raw-development.d.ts +15 -0
  9. package/dist/capture/native-raw-development.js +12 -6
  10. package/dist/capture/native-raw-development.js.map +1 -1
  11. package/dist/capture/raw-development-kernel.d.ts +10 -3
  12. package/dist/capture/raw-development-kernel.js +25 -6
  13. package/dist/capture/raw-development-kernel.js.map +1 -1
  14. package/dist/core/internal-radiance-evaluator.d.ts +5 -2
  15. package/dist/core/internal-radiance-evaluator.js.map +1 -1
  16. package/dist/core/version.d.ts +1 -1
  17. package/dist/core/version.js +1 -1
  18. package/dist/core/version.js.map +1 -1
  19. package/dist/facade/defocus-image-space-provider.d.ts +109 -0
  20. package/dist/facade/defocus-image-space-provider.js +359 -0
  21. package/dist/facade/defocus-image-space-provider.js.map +1 -0
  22. package/dist/facade/diffraction-provider.d.ts +16 -0
  23. package/dist/facade/diffraction-provider.js +3 -3
  24. package/dist/facade/diffraction-provider.js.map +1 -1
  25. package/dist/facade/display-view.d.ts +21 -0
  26. package/dist/facade/display-view.js +66 -8
  27. package/dist/facade/display-view.js.map +1 -1
  28. package/dist/facade/simulate-capture.d.ts +111 -2
  29. package/dist/facade/simulate-capture.js +220 -44
  30. package/dist/facade/simulate-capture.js.map +1 -1
  31. package/dist/facade/simulate-display-view.js +7 -3
  32. package/dist/facade/simulate-display-view.js.map +1 -1
  33. package/dist/gpu/display-view-quality-gpu.d.ts +2 -0
  34. package/dist/gpu/display-view-quality-gpu.js +57 -13
  35. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  36. package/dist/gpu/display-view-speed-gpu.d.ts +2 -0
  37. package/dist/gpu/display-view-speed-gpu.js +45 -16
  38. package/dist/gpu/display-view-speed-gpu.js.map +1 -1
  39. package/dist/gpu/image-kernel-accelerator.js +3 -0
  40. package/dist/gpu/image-kernel-accelerator.js.map +1 -1
  41. package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +4 -0
  42. package/dist/gpu/wgsl-display-view-quality-kernel.js +53 -2
  43. package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
  44. package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +15 -0
  45. package/dist/gpu/wgsl-display-view-speed-kernel.js +42 -1
  46. package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
  47. package/dist/index.d.ts +2 -2
  48. package/dist/index.js +1 -1
  49. package/dist/index.js.map +1 -1
  50. package/dist/optics/defocus-disc-kernel.d.ts +3 -2
  51. package/dist/optics/defocus-disc-kernel.js +3 -2
  52. package/dist/optics/defocus-disc-kernel.js.map +1 -1
  53. package/dist/optics/sensor-environment-query.d.ts +31 -0
  54. package/dist/optics/sensor-environment-query.js +45 -13
  55. package/dist/optics/sensor-environment-query.js.map +1 -1
  56. package/dist/processing/development-detail.d.ts +132 -0
  57. package/dist/processing/development-detail.js +325 -0
  58. package/dist/processing/development-detail.js.map +1 -0
  59. package/docs/API_REFERENCE.md +6 -1
  60. package/docs/QUICK_START.md +190 -12
  61. package/docs/USAGE.md +14 -3
  62. package/docs/api/capture-native-raw-development.md +16 -0
  63. package/docs/api/core-version.md +1 -1
  64. package/docs/api/exports.json +27 -2
  65. package/docs/api/facade-simulate-capture.md +128 -3
  66. package/docs/api/optics-defocus-disc-kernel.md +3 -2
  67. package/package.json +1 -1
@@ -131,7 +131,7 @@ async function renderDisplayViewResult(context, viewInternals) {
131
131
  * signal caches, lookup count and assumptions), so its results are those of separate calls.
132
132
  */
133
133
  function prepareView(context) {
134
- const { ahd, antiAliasing, aspect, axisChannelResponse, boxSamples, buildProvider, callerScene, chart, materialLayers, chartReport, chartSize, diffraction, diffractionPsf, fNumber, focalLengthMm, focusDistanceM, height, highlightMode, illuminanceLux, illuminant, illuminantOption, imagingArea, intentOf, metresPerFrameUnit, noiseSeed, outputOptions, pitch, preset, provider, regimeByChannel, resolvedIso, isoReport, standardExposureDeviationStops, standardExposureIlluminanceLux, greyCardDeviationStops, metering, sceneOption, scenePreset, shutterSeconds, subjectDistanceM, toneCurve, whiteBalanceOption, whiteBalanceState, width, margin, mode, nativeHeight, nativeWidth, sourceSha256 } = context;
134
+ const { ahd, antiAliasing, aspect, axisChannelResponse, boxSamples, buildProvider, callerScene, chart, materialLayers, chartReport, chartSize, diffraction, diffractionPsf, fNumber, focalLengthMm, focusDistanceM, height, highlightMode, exposureGain, illuminanceLux, illuminant, illuminantOption, imagingArea, intentOf, metresPerFrameUnit, noiseSeed, outputOptions, pitch, preset, provider, regimeByChannel, resolvedIso, isoReport, standardExposureDeviationStops, standardExposureIlluminanceLux, greyCardDeviationStops, metering, sceneOption, scenePreset, shutterSeconds, subjectDistanceM, toneCurve, whiteBalanceOption, whiteBalanceState, width, margin, mode, nativeHeight, nativeWidth, sourceSha256 } = context;
135
135
  const kelvinInput = context.kelvinWhiteBalanceInput;
136
136
  const portableKelvinWhiteBalance = kelvinInput ? () => resolvePortableColorTemperatureWhiteBalance(kelvinInput) : undefined;
137
137
  // The engine's illuminant formulas (Planckian, CIE A, daylight locus) evaluated with the portable power and e^x − 1, so
@@ -161,13 +161,16 @@ function prepareView(context) {
161
161
  radianceAt: viewProvider.radianceAt, imagingArea, focalLengthMm, focusDistanceM, subjectDistanceM, metresPerFrameUnit, caller: "simulateDisplayView" });
162
162
  const kernels = signalInput.kernels;
163
163
  // Readout moments per channel: normalized value k·e with variance k²·(e + σ_read²) plus the ADC quantization (1/12 code², times d² before a digital gain d).
164
+ // #556: a development exposure push G multiplies the normalized value before the per-site clip at white: k → G·k and the constant variance → G²·(…).
165
+ // Without a push G = 1, and x·1 = x exactly in IEEE 754 arithmetic, so the moments are bit-identical to those without the push.
164
166
  const readout = CHANNELS.map((channel) => {
165
167
  const { readoutProfile, regimeId } = regimeByChannel[channel];
166
168
  const resolved = resolveSensorReadoutRegime({ profile: readoutProfile, regimeId });
167
169
  const k = relativePerElectron[channel], digitalGain = resolved.regime.adc.digitalGain ?? 1, gain = resolved.regime.systemConversionGainElectronsPerCode.value;
168
170
  const codeSpan = digitalGain / (gain * k), read = resolved.combinedReadNoiseRmsElectrons;
169
171
  const quantizationCodes = digitalGain * digitalGain / 12 + (digitalGain === 1 ? 0 : 1 / 12);
170
- return { perElectron: k, darkElectrons: DARK_CURRENT_ELECTRONS_PER_SECOND * shutterSeconds, constantVariance: k * k * read * read + quantizationCodes / (codeSpan * codeSpan) };
172
+ return { perElectron: exposureGain * k, darkElectrons: DARK_CURRENT_ELECTRONS_PER_SECOND * shutterSeconds,
173
+ constantVariance: exposureGain * exposureGain * (k * k * read * read + quantizationCodes / (codeSpan * codeSpan)) };
171
174
  });
172
175
  const phases = bilinearPhaseProfiles(), demosaicTable = [];
173
176
  for (const phase of phases)
@@ -273,7 +276,8 @@ function prepareView(context) {
273
276
  framedWidthM: 2 * metresPerFrameUnit, framedHeightM: 2 * metresPerFrameUnit * aspect, ...(chartReport ? { chart: chartReport } : {}), sourceSha256 },
274
277
  diagnostics: { sampleCount: rendered.sampleCount, siteEvaluations: rendered.siteCount, sceneLookups: signal.lookups, detailPixelCount: rendered.detailPixelCount,
275
278
  uniformPixelCount: rendered.uniformPixelCount, ahdCorrectedPixelCount: rendered.ahdCorrectedPixelCount, timingsMs: { view: viewMs, total: Date.now() - started },
276
- fast: Object.freeze({ ...context.fastReport, assurance: execution.backend === "webgpu-f32" ? "approximation-with-a-priori-bound" : context.fastReport.assurance, execution }) },
279
+ fast: Object.freeze({ ...context.fastReport, assurance: execution.backend === "webgpu-f32" ? "approximation-with-a-priori-bound" : context.fastReport.assurance, execution }),
280
+ highlight: Object.freeze({ saturatedPixelCount: rendered.saturatedPixelCount, statistic: "expected-value" }) },
277
281
  provenance: { scientificStatus: "approximation", cameraPresetId: preset.presetId, cameraPresetVersion: preset.presetVersion, evidence: [...FACADE_EVIDENCE, ...preset.evidence],
278
282
  composedContracts: ["calculateEnvironmentSensorPhotoSignal", "resolveSensorReadoutRegime", "calculateSiteEffectiveSaturationCode", ...(diffraction ? ["createDiffractionLimitedPsfProfile", "resolveLensPsfConvolutionKernels"] : []),
279
283
  ...(antiAliasing ? ["resolveAntiAliasingSpatialKernel"] : []), "prepareSensorColorDevelopment", "display view estimator"],
@@ -1 +1 @@
1
- {"version":3,"file":"simulate-display-view.js","sourceRoot":"","sources":["../../src/facade/simulate-display-view.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The public entry point of the display view (`simulateDisplayView`) and its renderer. `simulate-capture.ts` resolves the\n * request (`runCapture`) and calls the renderer it is given, so a bundle that imports only `simulateCapture` or\n * `simulateIdealReference` does not contain the display view (`display-view.ts`) or the portable evaluations it uses.\n * The design and its error analysis are in docs/DISPLAY_VIEW.md.\n */\n\nimport { ENGINE_API_VERSION } from \"../core/version.js\";\nimport { resolvePortableColorTemperatureWhiteBalance, type ResolvedWhiteBalanceState } from \"../color/white-balance.js\";\nimport { resolveCaptureColorModel } from \"../color/capture-color.js\";\nimport { prepareSensorColorDevelopment } from \"../color/sensor-color-development.js\";\nimport { buildExpectedSignalInput } from \"./expected-signal-setup.js\";\nimport type { DisplayViewExpectedSignalInput } from \"./expected-signal.js\";\nimport { resolveSensorReadoutRegime } from \"../sensor/raw-readout.js\";\nimport { resolvePortableChartScene, type ChartScene } from \"./chart-scenes.js\";\nimport { resolvePortableCaptureIlluminant, calculateIlluminantIrradianceScale } from \"./scene-radiance.js\";\nimport { ahdCandidateKernels, computeDisplayViewCorrectionStates, createDisplayViewExpectedSignal, displayViewCorrectionKey, renderDisplayView, type DisplayViewChannelReadout,\n type DisplayViewCorrectionSetup, type DisplayViewCorrectionStateKeys, type DisplayViewCorrectionStateSet, type DisplayViewExpectedSignal, type DisplayViewRenderResult, type DisplayViewSetup,\n EXACT_AREA_MEAN_MAX_PIXELS } from \"./display-view.js\";\nimport { runCapture, apertureNodeOffsets, bilinearPhaseProfiles, clockMs, fail, sceneIlluminantWhiteBalance, CAMERA_TO_XYZ, CHANNELS, DARK_CURRENT_ELECTRONS_PER_SECOND, FACADE_EVIDENCE,\n SIMULATE_CAPTURE_FACADE_VERSION, DISPLAY_VIEW_WITHOUT_VIEW, allowKeys, parseDisplayViewOption, type DisplayViewResult, type DisplayViewRunContext, type ParsedDisplayView,\n type SimulateCaptureAssumption, type SimulateCaptureOptions, type SimulateDisplayViewOptions } from \"./simulate-capture.js\";\nimport { createHostYield } from \"./host-yield.js\";\nimport { createDefocusDiscSiteKernel } from \"../optics/defocus-disc-kernel.js\";\nimport { cpuDisplayViewExecution, parsePrepareDisplayViewOptions, type DisplayViewExecution, type DisplayViewGpuRequest, type PrepareDisplayViewOptions } from \"./display-view-gpu.js\";\nimport type { DisplayViewGpuSession } from \"./display-view-gpu-session.js\";\n\nexport { serializeDisplayViewCorrectionStates, bindDisplayViewCorrectionStates, type DisplayViewCorrectionStateKeys, type DisplayViewCorrectionStateSet } from \"./display-view.js\";\n\n/**\n * The display view of a capture request: the image the real full-resolution capture (`simulateCapture(options)`) would\n * give after it is resized to `view.width` × `view.height` by area averaging in linear light, estimated at a cost that\n * follows the display pixels, not the capture's. Optics (lens diffraction, the anti-aliasing filter, the pixel aperture)\n * act at the real pixel pitch; the colour mosaic, demosaic and development are those of the real pixels; the noise is\n * that of the average of the real pixels, demosaic correlation included; exposure, white balance and tone are the\n * capture's. The result is labelled `kind: \"display-view\"`; it is not a capture.\n * @see docs/DISPLAY_VIEW.md and docs/QUICK_START.md, \"Display view\".\n */\nexport async function simulateDisplayView(options: SimulateCaptureOptions, view: SimulateDisplayViewOptions): Promise<DisplayViewResult> {\n return await runCapture(options, \"display-view\", view, (context) => renderDisplayViewResult(context)) as DisplayViewResult;\n}\n/** Options of one {@link PreparedDisplayView} render. */\nexport interface PreparedDisplayViewRenderOptions {\n /** Aborting cancels this render only; the promise rejects with a domain error. The request's own `signal` applies to preparing only. */\n signal?: AbortSignal;\n}\n/**\n * 2.7: a display-view request resolved once (`prepareDisplayView`). `render(view)` gives the same result as\n * `simulateDisplayView(options, view)` for the prepared options, byte for byte (samples, view, exposure, scene, diagnostics\n * and assumptions; only `diagnostics.timingsMs` differ, and they cover the render only), without repeating the request's\n * setup: use it to render one view in many regions, for example on each worker of a progressive display.\n */\nexport interface PreparedDisplayView {\n /**\n * Renders a view of the prepared request. Renders may run concurrently; they share no state except read-only setup and the\n * realm's AHD correction states, which never change a byte (docs/DISPLAY_VIEW.md, \"AHD at low signal\"). With `gpu: \"auto\"`\n * or `\"require\"` (#481) GPU renders of one prepared view run one at a time on its device, and `diagnostics.fast.execution`\n * says whether the GPU or the CPU reference rendered the view, and why.\n */\n render(view: SimulateDisplayViewOptions, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewResult>;\n /**\n * 2.11 (#481): releases the WebGPU device the view acquired (none with `gpu: \"off\"`, or when `gpuDevice` gave an accelerator,\n * whose device its owner keeps). Later renders run the CPU reference labelled `fallbackReason: \"disposed\"` (`\"auto\"`) or fail\n * with that reason (`\"require\"`). Idempotent.\n */\n dispose(): void;\n /**\n * 2.10 (#447): the key of this request's AHD low-signal correction states, or null when the request has no AHD\n * (`output.demosaic` other than \"ahd\"). Every input of the key is fixed when the request is prepared; two prepared views\n * with the same key read the same states.\n */\n correctionKey(): string | null;\n /**\n * 2.10 (#447): the grid keys of every correction state a render of `view` reads (ascending, whether or not this realm holds\n * them), found by a render of the view's region that records the states instead of computing them. No image is returned;\n * it costs about one render whose states are all held. Fails with an InvalidConfigurationError when the request has no AHD.\n */\n collectCorrectionStates(view: SimulateDisplayViewOptions, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewCorrectionStateKeys>;\n /**\n * 2.10 (#447): computes the correction states of `gridKeys` (from `collectCorrectionStates`, or a share of them) as a render\n * would, stores them in this realm's cache and returns their values, for {@link bindDisplayViewCorrectionStates} in\n * another realm. States this realm holds are read, not computed. Yields and honours `signal` like `render`. Fails with an\n * InvalidConfigurationError when the request has no AHD or a grid key is out of range.\n */\n computeCorrectionStates(gridKeys: Int32Array, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewCorrectionStateSet>;\n}\n/**\n * 2.7 (#387): resolves a {@link simulateDisplayView} request once, without a view, and returns a handle whose `render(view)`\n * renders its views. The setup it does once (request validation, the camera, lens, scene, chart and illuminant, the channel\n * responses through the environment chain, the diffraction kernels, readout moments, demosaic tables and colour matrix) costs\n * about 0.3–1.3 s per call on a 24 MP request; a region costs only its own pixels. Errors in the request are raised here;\n * errors in the view by `render`.\n *\n * 2.11 (#481): `prepareOptions.gpu` chooses the renderer: `\"off\"` (default) is the CPU reference, today's bytes; `\"auto\"` renders\n * on WebGPU when a conforming device is available and the request is supported, else on the CPU, labelled; `\"require\"` fails\n * instead of falling back (`ImageKernelExecutionError`, acquisition failures here, later ones from `render`). `gpuDevice` is a\n * WebGPU entry point or an `ImageKernelAccelerator` whose device the view shares; without it the engine acquires one device\n * for the prepared view (the request's `signal` aborts the acquisition) and `dispose()` releases it. The realm's\n * `setWebGpuEnabled(false)` vetoes both GPU modes (`webgpu-disabled`). See docs/DISPLAY_VIEW.md, \"Rendering on the GPU\".\n * @see docs/QUICK_START.md, \"Display view\".\n */\nexport async function prepareDisplayView(options: SimulateCaptureOptions, prepareOptions?: PrepareDisplayViewOptions): Promise<PreparedDisplayView> {\n const gpuOptions = parsePrepareDisplayViewOptions(prepareOptions);\n let frameWidth = 0, frameHeight = 0;\n const prepared = await runCapture(options, \"display-view\", DISPLAY_VIEW_WITHOUT_VIEW, (context) => {\n frameWidth = context.width; frameHeight = context.height;\n return Promise.resolve(prepareView(context));\n }) as PreparedViewParts;\n // The GPU code is loaded only when a GPU mode asks for it, so bundles on the default stay without it.\n const session: DisplayViewGpuSession | null = gpuOptions.gpu === \"off\" ? null :\n await (await import(\"./display-view-gpu-session.js\")).openDisplayViewGpuSession(gpuOptions, prepared.gpuRequest, (options as { signal?: AbortSignal }).signal);\n /** One call's start times, cancellation (its own signal) and yielding. */\n const runOf = (renderOptions: PreparedDisplayViewRenderOptions | undefined): ViewRun => {\n const started = Date.now(), viewStarted = clockMs();\n const signal = renderOptions === undefined ? undefined : allowKeys(renderOptions, \"render options\", [\"signal\"]).signal as AbortSignal | undefined;\n if (signal !== undefined && (typeof signal !== \"object\" || signal === null || typeof signal.aborted !== \"boolean\")) fail(\"signal must be an AbortSignal.\");\n const checkAbort = (): void => { if (signal?.aborted) fail(\"simulateCapture aborted.\"); };\n checkAbort();\n return { started, viewStarted, checkAbort, yieldControl: createHostYield().yieldControl, signal };\n };\n const correctionOf = (caller: string): DisplayViewCorrectionSetup => prepared.correction ??\n fail(caller + \": the prepared request has no AHD low-signal correction (it applies with output.demosaic \\\"ahd\\\").\");\n const handle: PreparedDisplayView = Object.freeze({\n async render(view: SimulateDisplayViewOptions, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewResult> {\n const run = runOf(renderOptions);\n const parsed = parseDisplayViewOption(view, frameWidth, frameHeight);\n return await prepared.render(parsed, run, undefined, session);\n },\n dispose(): void { session?.dispose(); },\n correctionKey(): string | null { return prepared.correction ? displayViewCorrectionKey(prepared.correction) : null; },\n async collectCorrectionStates(view: SimulateDisplayViewOptions, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewCorrectionStateKeys> {\n const run = runOf(renderOptions), correction = correctionOf(\"collectCorrectionStates\");\n const parsed = parseDisplayViewOption(view, frameWidth, frameHeight);\n return { key: displayViewCorrectionKey(correction)!, gridKeys: await prepared.collect(parsed, run) };\n },\n async computeCorrectionStates(gridKeys: Int32Array, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewCorrectionStateSet> {\n const run = runOf(renderOptions), correction = correctionOf(\"computeCorrectionStates\");\n return await computeDisplayViewCorrectionStates({ ...correction, yieldControl: run.yieldControl, checkAbort: run.checkAbort }, gridKeys);\n }\n });\n PREPARED_INTERNALS.set(handle, async (view, renderOptions) => {\n const internals: ViewInternals = {};\n const result = await prepared.render(parseDisplayViewOption(view, frameWidth, frameHeight), runOf(renderOptions), internals, session);\n return { result, internals: internals.value! };\n });\n return handle;\n}\n/** The internal render of each prepared view (the same render as `render`, keeping its renderer's result). */\nconst PREPARED_INTERNALS = new WeakMap<PreparedDisplayView, (view: SimulateDisplayViewOptions, renderOptions?: PreparedDisplayViewRenderOptions) =>\n Promise<{ result: DisplayViewResult; internals: DisplayViewRenderResult }>>();\n/**\n * Internal (not exported from the package): renders a view of a prepared view as `render` does (the same GPU session and labels)\n * and also returns the renderer's noise-free expected linear values and noise standard deviations, whichever renderer ran (#480's\n * GPU producer, `scripts/lib/display-view-gpu-page.mjs`).\n */\nexport async function renderPreparedDisplayViewWithInternals(prepared: PreparedDisplayView, view: SimulateDisplayViewOptions, renderOptions?: PreparedDisplayViewRenderOptions):\n Promise<{ result: DisplayViewResult; internals: DisplayViewRenderResult }> {\n const render = PREPARED_INTERNALS.get(prepared);\n if (!render) fail(\"renderPreparedDisplayViewWithInternals needs a view returned by prepareDisplayView.\");\n return await render(view, renderOptions);\n}\n/**\n * Internal (not exported from the package): the display view plus its noise-free expected linear values and noise standard\n * deviations, for the validation scripts and tests.\n */\nexport async function simulateDisplayViewWithInternals(options: SimulateCaptureOptions, view: SimulateDisplayViewOptions):\n Promise<{ result: DisplayViewResult; internals: DisplayViewRenderResult; signal: DisplayViewExpectedSignal; setup: DisplayViewSetup; signalInput: DisplayViewExpectedSignalInput }> {\n const internals: ViewInternals = {};\n const result = await runCapture(options, \"display-view\", view, (context) => renderDisplayViewResult(context, internals)) as DisplayViewResult;\n return { result, internals: internals.value!, signal: internals.signal!, setup: internals.setup!, signalInput: internals.signalInput! };\n}\n\n/** AHD low-signal correction (display view): draws per flat-neighbourhood state, and the pixel noise (linear light) above which it applies. */\nconst DISPLAY_VIEW_AHD_CORRECTION_DRAWS = 2048, DISPLAY_VIEW_AHD_CORRECTION_THRESHOLD = 0.01;\n\ntype ViewInternals = { value?: DisplayViewRenderResult; signal?: DisplayViewExpectedSignal;\n /** #478: the render's setup and the expected signal's input, for the GPU display view's tests. */\n setup?: DisplayViewSetup; signalInput?: DisplayViewExpectedSignalInput };\n/** What one render of a prepared view needs from its call: its start times, cancellation and yielding. */\ninterface ViewRun { started: number; viewStarted: number; checkAbort: () => void; yieldControl: () => Promise<void>; signal?: AbortSignal | undefined }\ntype RenderPreparedView = (view: ParsedDisplayView, run: ViewRun, viewInternals?: ViewInternals, gpu?: DisplayViewGpuSession | null) => Promise<DisplayViewResult>;\n/**\n * A prepared request: its render, its collect pass (#447: the grid keys of the correction states a view's region reads) and\n * the inputs of its correction states (undefined without AHD).\n */\ninterface PreparedViewParts {\n render: RenderPreparedView;\n collect(view: ParsedDisplayView, run: ViewRun): Promise<Int32Array>;\n correction: DisplayViewCorrectionSetup | undefined;\n /** #481: what a GPU renderer is asked to support. */\n gpuRequest: DisplayViewGpuRequest;\n}\n\n/** Renders the display view of a resolved request (the last step of `runCapture` for \"display-view\"). */\nasync function renderDisplayViewResult(context: DisplayViewRunContext, viewInternals?: ViewInternals): Promise<DisplayViewResult> {\n const viewStarted = clockMs();\n return await prepareView(context).render(context.parsedView!, { started: context.started, viewStarted, checkAbort: context.checkAbort, yieldControl: context.yieldControl }, viewInternals);\n}\n\n/**\n * Internal (#387): the part of a display view that depends only on the request, done once (the portable illuminant, chart and\n * white balance, the channel responses, query offsets, diffraction kernels, readout moments, demosaic tables and colour\n * matrix). The returned function renders one view from it; it keeps no state between renders (each has its own expected-\n * signal caches, lookup count and assumptions), so its results are those of separate calls.\n */\nfunction prepareView(context: DisplayViewRunContext): PreparedViewParts {\n const { ahd, antiAliasing, aspect, axisChannelResponse, boxSamples, buildProvider, callerScene, chart, materialLayers, chartReport, chartSize, diffraction, diffractionPsf, fNumber, focalLengthMm, focusDistanceM, height, highlightMode, illuminanceLux, illuminant, illuminantOption, imagingArea, intentOf, metresPerFrameUnit, noiseSeed, outputOptions, pitch, preset, provider, regimeByChannel, resolvedIso, isoReport, standardExposureDeviationStops, standardExposureIlluminanceLux, greyCardDeviationStops, metering, sceneOption, scenePreset, shutterSeconds, subjectDistanceM, toneCurve, whiteBalanceOption, whiteBalanceState, width, margin, mode, nativeHeight, nativeWidth, sourceSha256 } = context;\n const kelvinInput = context.kelvinWhiteBalanceInput;\n const portableKelvinWhiteBalance = kelvinInput ? (): ResolvedWhiteBalanceState => resolvePortableColorTemperatureWhiteBalance(kelvinInput) : undefined;\n // The engine's illuminant formulas (Planckian, CIE A, daylight locus) evaluated with the portable power and e^x − 1, so\n // the view's radiances, irradiance scale and scene-illuminant white balance have the same bits in every JavaScript\n // engine; they differ from the capture's own by at most a few ulps (docs/DISPLAY_VIEW.md, \"Same bytes in every engine\").\n const viewIlluminant = resolvePortableCaptureIlluminant(illuminantOption), viewIrradianceScale = calculateIlluminantIrradianceScale(viewIlluminant.shape, illuminanceLux);\n const viewProvider = buildProvider(viewIlluminant, viewIrradianceScale);\n const viewWhiteBalanceState = whiteBalanceOption === \"scene-illuminant\" ? sceneIlluminantWhiteBalance(viewIlluminant) : portableKelvinWhiteBalance ? portableKelvinWhiteBalance() : whiteBalanceState;\n // The chart's materials likewise (a step wedge's geometric levels use the portable power); same geometry and order.\n const viewChart = chart ? resolvePortableChartScene({ scene: sceneOption as ChartScene, aspect: chartSize ? chartSize.heightM / chartSize.widthM : aspect }) : undefined;\n if (chart && viewChart!.materials.length !== chart.materials.length) fail(\"simulateDisplayView: the chart's materials could not be resolved portably.\");\n const { electronsPerRadiance, wavelengths, relativePerElectron } = axisChannelResponse(\"simulateDisplayView\");\n const perNode = CHANNELS.map((c) => Float64Array.from(wavelengths, (nm) => electronsPerRadiance[c].get(nm) ?? 0)) as [Float64Array, Float64Array, Float64Array];\n // The tabulated expected signal's input (#394: shared with the capture's tabulated RAW path).\n const sceneMaterials = viewChart ? viewChart.materials : callerScene?.kind === \"material-function\" ? callerScene.materials : undefined;\n // Defocus (#492): the geometric disc on the site lattice, combined with the diffraction kernels in the tables (expected-signal-setup.ts).\n const defocusDisc = context.defocus, defocusKernel = defocusDisc && defocusDisc.diameterSites > 0 ? createDefocusDiscSiteKernel(defocusDisc.diameterSites) : null;\n // The combined radius is at most 32 + 64 = 96 sites (the diffraction and disc caps), as in the capture.\n const diffractionRadius = diffraction ? diffraction.kernelRadiusSamples : 0, combinedRadius = defocusKernel ? diffractionRadius + defocusKernel.radius : diffractionRadius;\n const { offsets, signalInput } = buildExpectedSignalInput({ nativeWidth, nativeHeight, width, wavelengths, perNode, apertureNodes: apertureNodeOffsets(boxSamples), boxSamples,\n antiAliasing, pitch, defocus: defocusKernel, diffraction: diffraction ? { radius: diffraction.kernelRadiusSamples, psf: diffractionPsf!.configuration.psf, profileWavelengths: diffraction.profile.axes.wavelengthNm } : undefined,\n materials: sceneMaterials && provider.chartMaterialAt ? { materialAt: provider.chartMaterialAt,\n list: [...sceneMaterials.map((m, index) => (m.kind === \"neutral\" ? { neutral: m.reflectance } : { radiance: (nm: number): number => viewProvider.materialRadiance!(index, nm) })),\n ...(chartSize ? [{ neutral: chartSize.surroundReflectance }] : [])],\n whiteRadiance: (nm: number): number => viewIrradianceScale * viewIlluminant.shape.evaluate(nm) / Math.PI } : undefined,\n radianceAt: viewProvider.radianceAt, imagingArea, focalLengthMm, focusDistanceM, subjectDistanceM, metresPerFrameUnit, caller: \"simulateDisplayView\" });\n const kernels = signalInput.kernels;\n // Readout moments per channel: normalized value k·e with variance k²·(e + σ_read²) plus the ADC quantization (1/12 code², times d² before a digital gain d).\n const readout = CHANNELS.map((channel): DisplayViewChannelReadout => {\n const { readoutProfile, regimeId } = regimeByChannel[channel];\n const resolved = resolveSensorReadoutRegime({ profile: readoutProfile as Parameters<typeof resolveSensorReadoutRegime>[0][\"profile\"], regimeId });\n const k = relativePerElectron[channel], digitalGain = resolved.regime.adc.digitalGain ?? 1, gain = resolved.regime.systemConversionGainElectronsPerCode.value;\n const codeSpan = digitalGain / (gain * k), read = resolved.combinedReadNoiseRmsElectrons;\n const quantizationCodes = digitalGain * digitalGain / 12 + (digitalGain === 1 ? 0 : 1 / 12);\n return { perElectron: k, darkElectrons: DARK_CURRENT_ELECTRONS_PER_SECOND * shutterSeconds, constantVariance: k * k * read * read + quantizationCodes / (codeSpan * codeSpan) };\n }) as [DisplayViewChannelReadout, DisplayViewChannelReadout, DisplayViewChannelReadout];\n const phases = bilinearPhaseProfiles(), demosaicTable: { dx: number; dy: number; weight: number }[][][] = [];\n for (const phase of phases) demosaicTable[phase.phaseY * 2 + phase.phaseX] = CHANNELS.map((c) => phase.profile.kernels.find((k) => k.outputChannelId === c)!.contributions\n .map((t) => ({ dx: t.offsetX, dy: t.offsetY, weight: t.weight })));\n const viewIntent = intentOf(viewWhiteBalanceState), viewGains = viewIntent ? [viewIntent.channelGains.red, viewIntent.channelGains.green, viewIntent.channelGains.blue] : null;\n const colour = prepareSensorColorDevelopment(CAMERA_TO_XYZ as unknown as Parameters<typeof prepareSensorColorDevelopment>[0], viewGains, highlightMode);\n const toSrgb = resolveCaptureColorModel().xyzToCameraRgb, m = colour.cameraToXyz;\n const matrix = [0, 1, 2].map((r) => [0, 1, 2].map((c) => toSrgb[r]![0]! * m[0]![c]! + toSrgb[r]![1]! * m[1]![c]! + toSrgb[r]![2]! * m[2]![c]!));\n // Reach of a footprint's pixels into the scene, in sites: the demosaic (1), the largest query offset and the kernel radius.\n const reachSites = (ahd ? 3 : 1) + Math.ceil(Math.max(0, ...offsets.map((o) => Math.max(Math.abs(o.x), Math.abs(o.y))))) + (kernels ? kernels.radius : 0);\n // The inputs of the AHD correction states (fixed here, so the correction key is too; #447).\n const gains = colour.appliedGains as [number, number, number], clipLevel = Math.min(...colour.appliedGains), viewToneCurve = toneCurve as \"identity\" | \"positive-reinhard-per-channel\";\n const ahdCorrection = ahd ? { labMatrix: CAMERA_TO_XYZ.map((row) => row.map((value, c) => value * (viewGains ? viewGains[c]! : 1))), drawsPerState: DISPLAY_VIEW_AHD_CORRECTION_DRAWS,\n thresholdVariance: DISPLAY_VIEW_AHD_CORRECTION_THRESHOLD * DISPLAY_VIEW_AHD_CORRECTION_THRESHOLD } : undefined;\n const ahdCandidates = ahd ? [0, 1, 2, 3].map((p) => ahdCandidateKernels(p % 2, Math.floor(p / 2))) : undefined;\n // #491: a fixed-size chart's placement for the GPU material lookup (the provider's chart-local units cu = u·m/h and the surround beyond the chart).\n const placement = chartSize ? { chartUnitsPerFrameUnit: metresPerFrameUnit / (chartSize.widthM / 2), aspect: chartSize.heightM / chartSize.widthM } : null;\n /** The renderer's setup of one view (with `ahdCollect`, a collect pass), and its expected signal. */\n const setupOf = (v: ParsedDisplayView, viewRegion: { x: number; y: number; width: number; height: number }, { checkAbort, yieldControl }: ViewRun,\n ahdCollect?: Set<number>): { setup: DisplayViewSetup; signal: DisplayViewExpectedSignal } => {\n // The native columns the region's windows span, beyond one window's width: a filled band need not be wider (a speed hint).\n const signal = createDisplayViewExpectedSignal(signalInput, Math.ceil((viewRegion.width + 2) * nativeWidth / v.width));\n return { signal, setup: { frameWidth: width, frameHeight: height, margin, nativeWidth, nativeHeight, viewWidth: v.width, viewHeight: v.height,\n region: viewRegion, samplesPerAxis: v.samplesPerAxis, reachSites, bitDepth: v.bitDepth, seed: noiseSeed, signal, readout, demosaic: demosaicTable,\n ...(ahdCandidates && ahdCorrection ? { candidates: ahdCandidates, ahdCorrection } : {}), ...(ahdCollect ? { ahdCollect } : {}),\n gains, clipLevel, matrix, toneCurve: viewToneCurve, yieldControl, checkAbort, gpu: { signalInput, chart: viewChart ?? null, layers: materialLayers ?? null, placement, ...(defocusKernel ? { defocusRadius: defocusKernel.radius } : {}) } } };\n };\n const correction: DisplayViewCorrectionSetup | undefined = ahdCorrection ? { seed: noiseSeed, readout, gains, clipLevel, matrix, toneCurve: viewToneCurve, ahdCorrection } : undefined;\n const collect = async (v: ParsedDisplayView, run: ViewRun): Promise<Int32Array> => {\n const keys = new Set<number>();\n await renderDisplayView(setupOf(v, v.region ?? { x: 0, y: 0, width: v.width, height: v.height }, run, keys).setup);\n return Int32Array.from(keys).sort();\n };\n // #492: out of focus the view reads the defocus disc (its kernel in signalInput.kernels); the GPU Quality site pass gathers it (step 2c).\n const gpuRequest: DisplayViewGpuRequest = { ahd, defocus: defocusKernel !== null, diffraction: diffraction !== undefined, antiAliasing: antiAliasing !== undefined, boxSamples, toneCurve: viewToneCurve,\n scene: chart ? \"chart\" : materialLayers ? \"material-layers\" : callerScene!.kind };\n const render: RenderPreparedView = async (v, run, viewInternals, gpu) => {\n const { started, viewStarted } = run;\n const assumptions: SimulateCaptureAssumption[] = [...context.assumptions];\n const assume = (id: string, kind: SimulateCaptureAssumption[\"kind\"], value: unknown, explanation: string): void => { assumptions.push({ id, kind, value, explanation }); };\n const viewRegion = v.region ?? { x: 0, y: 0, width: v.width, height: v.height };\n const { setup, signal } = setupOf(v, viewRegion, run);\n // #481: the GPU session renders on the device when it can, else through the CPU reference, and labels which ran.\n const cpu = (): Promise<DisplayViewRenderResult> => renderDisplayView(setup);\n const { rendered, execution }: { rendered: DisplayViewRenderResult; execution: DisplayViewExecution } = gpu ? await gpu.render(setup, run.signal, cpu)\n : { rendered: await cpu(), execution: cpuDisplayViewExecution(\"off\", null, null, null) };\n if (viewInternals) { viewInternals.value = rendered; viewInternals.signal = signal; viewInternals.setup = setup; viewInternals.signalInput = signalInput; }\n const viewMs = clockMs() - viewStarted, scaleX = width / v.width, scaleY = height / v.height;\n assume(\"view.definition\", \"model\", { resampling: \"area-average-linear-light\", width: v.width, height: v.height, frameWidth: width, frameHeight: height, scaleX, scaleY },\n \"The image the full-resolution capture of this request would give after resizing to \" + v.width + \" × \" + v.height + \": each display pixel is the area-weighted mean, in linear light (sRGB samples decoded with the sRGB EOTF), \" +\n \"of the real output pixels its rectangle covers (\" + scaleX + \" × \" + scaleY + \" real pixels), then sRGB-encoded and rounded. The real capture's own samples are rounded to the view's bit depth before averaging.\");\n const uniformSamplesPerAxis = Math.max(1, Math.round(v.samplesPerAxis / 4));\n const siteSentence = \"the expected electrons of the real sites its demosaic reads are exact at the real pitch (the scene sampled at those sites through the pixel aperture, \" +\n \"anti-aliasing filter and diffraction kernels, with the capture's own query arithmetic, so the colour mosaic and its aliasing are the real sensor's), and the per-site clip at white, the highlight clip, the tone curve \" +\n \"and the clip to [0, 1] act on the pixel's own noise distribution, approximated as normal.\";\n // 2.8 (#393): where a footprint holds at most 25 real pixels (and at most K²), every real pixel of it is evaluated once with its exact weight.\n if (rendered.estimation === \"exact-area-mean\") {\n assume(\"view.estimation\", \"model\", { method: \"exact-area-mean-over-real-pixels\", samplesPerAxis: v.samplesPerAxis, realPixelsPerDisplayPixel: scaleX * scaleY,\n evaluatedRealPixels: rendered.sampleCount },\n \"Each display pixel's expected value is the exact area mean of the real pixels its rectangle covers: every real pixel it touches is evaluated once and weighted by its overlap with the rectangle \" +\n \"(w_j / A, summing to 1), so there is no sampling error. This applies because each rectangle holds \" + scaleX * scaleY + \" real pixels (\" + scaleX + \" × \" + scaleY + \"), at most \" + EXACT_AREA_MEAN_MAX_PIXELS + \" and at most K² = \" + v.samplesPerAxis * v.samplesPerAxis + \"; coarser views use a stratified estimate, which costs less there. \" +\n \"For each real pixel \" + siteSentence);\n } else {\n assume(\"view.estimation\", \"model\", { method: \"stratified-monte-carlo-over-real-pixels\", samplesPerAxis: v.samplesPerAxis, uniformSamplesPerAxis,\n detailPixels: rendered.detailPixelCount, uniformPixels: rendered.uniformPixelCount },\n \"Each display pixel's expected value is the mean over K × K strata of its rectangle, one seeded uniformly jittered real pixel in each, so it is unbiased; the error is zero where the rectangle is uniform \" +\n \"and falls as K^-3/2 at an edge. K = \" + v.samplesPerAxis + \" where a fixed pilot grid over the rectangle (widened by the demosaic, filter and kernel reach) or a neighbouring pixel's grid finds more than one scene value, \" +\n \"K = \" + uniformSamplesPerAxis + \" elsewhere. For each sampled pixel \" + siteSentence);\n }\n assume(\"view.noise\", \"model\", { method: \"variance-of-the-area-mean\", distribution: \"normal\" },\n \"Noise of the mean of the real pixels: the covariance of the weighted sum of independent site noises (shot, dark, read and ADC), with the demosaic correlation (B_c = Σ β², in closed form from the rectangle) and the \" +\n \"expected slopes of the clips and the tone curve (Stein's lemma); the variance the linearization misses and the real pixels' output rounding are added per pixel. One correlated normal draw per display pixel, seeded \" +\n \"by sensor.noiseSeed: the same statistics as the resized capture, not the same realization.\");\n assume(\"view.demosaic\", \"model\", ahd ? { capture: \"ahd\", view: \"ahd-candidates-with-low-signal-correction\", correctedPixels: rendered.ahdCorrectedPixelCount,\n correctionDrawsPerState: DISPLAY_VIEW_AHD_CORRECTION_DRAWS, correctionThresholdLinearStd: DISPLAY_VIEW_AHD_CORRECTION_THRESHOLD } : { capture: \"bilinear\", view: \"bilinear\" },\n ahd ? \"AHD is non-linear only in its choice between two linear candidates (green along the rows or the columns, red and blue from colour differences). The view propagates both candidates' exact linear statistics \" +\n \"and averages them. Where a sampled pixel's noise exceeds \" + DISPLAY_VIEW_AHD_CORRECTION_THRESHOLD + \" (linear light), the choice reacts to the noise and shifts the colour, so the pixel adds the mean \" +\n \"difference between the engine's AHD steps and the two candidates on \" + DISPLAY_VIEW_AHD_CORRECTION_DRAWS + \" drawn noisy flat neighbourhoods (Poisson electrons plus read and ADC noise) with its channel means, \" +\n \"computed once per state of a logarithmic grid (8 steps per octave of the channel means) and interpolated trilinearly, a control variate with no per-pixel sampling noise; \" +\n \"the flat-neighbourhood state is an approximation at edges (docs/DISPLAY_VIEW.md, validation).\" :\n \"The bilinear demosaic's linear kernels, exactly.\");\n if (defocusKernel) {\n assume(\"view.defocus\", \"model\", { kernel: diffraction ? \"diffraction-convolved-with-disc\" : \"disc\", defocusKernelRadiusSites: defocusKernel.radius,\n diffractionKernelRadiusSites: diffraction ? diffractionRadius : null, kernelRadiusSites: combinedRadius, scientificStatus: \"approximation\" },\n \"The expected electrons of each real site read the scene on the site lattice through the defocus disc (\" + defocusKernel.diameterSites + \" sites across, a \" + defocusKernel.width + \" × \" +\n defocusKernel.width + \" window), as the capture's object-space convolution does; the estimators then run unchanged on the blurred signal. \" + (diffraction ?\n \"With lens.diffraction each spectral node's kernel is its diffraction kernel convolved with the disc (\" + (2 * combinedRadius + 1) + \" × \" + (2 * combinedRadius + 1) + \" taps): \" +\n \"an approximation, because the PSF of a defocused wave is not the in-focus Airy pattern convolved with a geometric disc.\" :\n \"The disc is the same at every spectral node (geometric optics).\"));\n }\n if (execution.backend === \"webgpu-f32\") {\n assume(\"view.execution\", \"model\", { backend: execution.backend, arithmetic: execution.arithmetic, errorBound: execution.errorBound, adapter: execution.adapter },\n \"Estimated on the GPU: this view was rendered by the WebGPU float32 display-view renderer, a labelled approximation of the float64 CPU reference within the a-priori \" +\n \"error bound reported in diagnostics.fast.execution.errorBound; it is not bit-identical to the reference. The device passed the engine's run-time conformance check first.\");\n }\n assume(\"view.source\", \"model\", { rendering: \"srgb\", format: v.format, ignoredCaptureOutput: [\"format\", \"colorEncoding\", \"bitDepth\", \"gamutMapping\", \"jpegQuantizationStep\", \"dng\", \"metadata\", \"maximumPixels\"].filter((k) => outputOptions[k] !== undefined) },\n \"The view shows the capture's sRGB rendering (its tone curve, white balance and highlight mode); the capture's file-format options do not apply to it.\");\n return Object.freeze({ kind: \"display-view\" as const, label: \"Display view: the full-resolution capture resized to \" + v.width + \" × \" + v.height + \" (estimated); not a capture.\",\n facadeVersion: SIMULATE_CAPTURE_FACADE_VERSION, engineApiVersion: ENGINE_API_VERSION,\n image: { width: viewRegion.width, height: viewRegion.height, format: v.format, samples: rendered.samples },\n view: { width: v.width, height: v.height, frameWidth: width, frameHeight: height, scaleX, scaleY, samplesPerAxis: v.samplesPerAxis, ...(v.region ? { region: { ...v.region } } : {}) },\n exposure: { mode, settings: { fNumber, shutterSeconds, iso: resolvedIso }, ev100: Math.log2(fNumber ** 2 / shutterSeconds), ...isoReport, standardExposureDeviationStops, standardExposureIlluminanceLux, greyCardDeviationStops, metering },\n scene: { sceneId: chart ? \"chart:\" + chart.preset : callerScene!.sceneId, preset: scenePreset, parameters: chart ? chart.parameters : {},\n illuminant: { id: illuminant.id, description: illuminant.description, illuminanceLux }, distanceM: subjectDistanceM,\n framedWidthM: 2 * metresPerFrameUnit, framedHeightM: 2 * metresPerFrameUnit * aspect, ...(chartReport ? { chart: chartReport } : {}), sourceSha256 },\n diagnostics: { sampleCount: rendered.sampleCount, siteEvaluations: rendered.siteCount, sceneLookups: signal.lookups, detailPixelCount: rendered.detailPixelCount,\n uniformPixelCount: rendered.uniformPixelCount, ahdCorrectedPixelCount: rendered.ahdCorrectedPixelCount, timingsMs: { view: viewMs, total: Date.now() - started },\n fast: Object.freeze({ ...context.fastReport, assurance: execution.backend === \"webgpu-f32\" ? \"approximation-with-a-priori-bound\" as const : context.fastReport.assurance, execution }) },\n provenance: { scientificStatus: \"approximation\" as const, cameraPresetId: preset.presetId, cameraPresetVersion: preset.presetVersion, evidence: [...FACADE_EVIDENCE, ...preset.evidence],\n composedContracts: [\"calculateEnvironmentSensorPhotoSignal\", \"resolveSensorReadoutRegime\", \"calculateSiteEffectiveSaturationCode\", ...(diffraction ? [\"createDiffractionLimitedPsfProfile\", \"resolveLensPsfConvolutionKernels\"] : []),\n ...(antiAliasing ? [\"resolveAntiAliasingSpatialKernel\"] : []), \"prepareSensorColorDevelopment\", \"display view estimator\"],\n limitations: [\"Estimated display view of the full-resolution capture: its expected value is a stratified Monte Carlo estimate and its noise is drawn from the variance of the area mean, so it has the resized capture's statistics, not its exact pixels; not a capture and not a measurement.\"] },\n assumptions: Object.freeze(assumptions.map((a) => Object.freeze(a))) });\n };\n return { render, collect, correction, gpuRequest };\n}\n"]}
1
+ {"version":3,"file":"simulate-display-view.js","sourceRoot":"","sources":["../../src/facade/simulate-display-view.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The public entry point of the display view (`simulateDisplayView`) and its renderer. `simulate-capture.ts` resolves the\n * request (`runCapture`) and calls the renderer it is given, so a bundle that imports only `simulateCapture` or\n * `simulateIdealReference` does not contain the display view (`display-view.ts`) or the portable evaluations it uses.\n * The design and its error analysis are in docs/DISPLAY_VIEW.md.\n */\n\nimport { ENGINE_API_VERSION } from \"../core/version.js\";\nimport { resolvePortableColorTemperatureWhiteBalance, type ResolvedWhiteBalanceState } from \"../color/white-balance.js\";\nimport { resolveCaptureColorModel } from \"../color/capture-color.js\";\nimport { prepareSensorColorDevelopment } from \"../color/sensor-color-development.js\";\nimport { buildExpectedSignalInput } from \"./expected-signal-setup.js\";\nimport type { DisplayViewExpectedSignalInput } from \"./expected-signal.js\";\nimport { resolveSensorReadoutRegime } from \"../sensor/raw-readout.js\";\nimport { resolvePortableChartScene, type ChartScene } from \"./chart-scenes.js\";\nimport { resolvePortableCaptureIlluminant, calculateIlluminantIrradianceScale } from \"./scene-radiance.js\";\nimport { ahdCandidateKernels, computeDisplayViewCorrectionStates, createDisplayViewExpectedSignal, displayViewCorrectionKey, renderDisplayView, type DisplayViewChannelReadout,\n type DisplayViewCorrectionSetup, type DisplayViewCorrectionStateKeys, type DisplayViewCorrectionStateSet, type DisplayViewExpectedSignal, type DisplayViewRenderResult, type DisplayViewSetup,\n EXACT_AREA_MEAN_MAX_PIXELS } from \"./display-view.js\";\nimport { runCapture, apertureNodeOffsets, bilinearPhaseProfiles, clockMs, fail, sceneIlluminantWhiteBalance, CAMERA_TO_XYZ, CHANNELS, DARK_CURRENT_ELECTRONS_PER_SECOND, FACADE_EVIDENCE,\n SIMULATE_CAPTURE_FACADE_VERSION, DISPLAY_VIEW_WITHOUT_VIEW, allowKeys, parseDisplayViewOption, type DisplayViewResult, type DisplayViewRunContext, type ParsedDisplayView,\n type SimulateCaptureAssumption, type SimulateCaptureOptions, type SimulateDisplayViewOptions } from \"./simulate-capture.js\";\nimport { createHostYield } from \"./host-yield.js\";\nimport { createDefocusDiscSiteKernel } from \"../optics/defocus-disc-kernel.js\";\nimport { cpuDisplayViewExecution, parsePrepareDisplayViewOptions, type DisplayViewExecution, type DisplayViewGpuRequest, type PrepareDisplayViewOptions } from \"./display-view-gpu.js\";\nimport type { DisplayViewGpuSession } from \"./display-view-gpu-session.js\";\n\nexport { serializeDisplayViewCorrectionStates, bindDisplayViewCorrectionStates, type DisplayViewCorrectionStateKeys, type DisplayViewCorrectionStateSet } from \"./display-view.js\";\n\n/**\n * The display view of a capture request: the image the real full-resolution capture (`simulateCapture(options)`) would\n * give after it is resized to `view.width` × `view.height` by area averaging in linear light, estimated at a cost that\n * follows the display pixels, not the capture's. Optics (lens diffraction, the anti-aliasing filter, the pixel aperture)\n * act at the real pixel pitch; the colour mosaic, demosaic and development are those of the real pixels; the noise is\n * that of the average of the real pixels, demosaic correlation included; exposure, white balance and tone are the\n * capture's. The result is labelled `kind: \"display-view\"`; it is not a capture.\n * @see docs/DISPLAY_VIEW.md and docs/QUICK_START.md, \"Display view\".\n */\nexport async function simulateDisplayView(options: SimulateCaptureOptions, view: SimulateDisplayViewOptions): Promise<DisplayViewResult> {\n return await runCapture(options, \"display-view\", view, (context) => renderDisplayViewResult(context)) as DisplayViewResult;\n}\n/** Options of one {@link PreparedDisplayView} render. */\nexport interface PreparedDisplayViewRenderOptions {\n /** Aborting cancels this render only; the promise rejects with a domain error. The request's own `signal` applies to preparing only. */\n signal?: AbortSignal;\n}\n/**\n * 2.7: a display-view request resolved once (`prepareDisplayView`). `render(view)` gives the same result as\n * `simulateDisplayView(options, view)` for the prepared options, byte for byte (samples, view, exposure, scene, diagnostics\n * and assumptions; only `diagnostics.timingsMs` differ, and they cover the render only), without repeating the request's\n * setup: use it to render one view in many regions, for example on each worker of a progressive display.\n */\nexport interface PreparedDisplayView {\n /**\n * Renders a view of the prepared request. Renders may run concurrently; they share no state except read-only setup and the\n * realm's AHD correction states, which never change a byte (docs/DISPLAY_VIEW.md, \"AHD at low signal\"). With `gpu: \"auto\"`\n * or `\"require\"` (#481) GPU renders of one prepared view run one at a time on its device, and `diagnostics.fast.execution`\n * says whether the GPU or the CPU reference rendered the view, and why.\n */\n render(view: SimulateDisplayViewOptions, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewResult>;\n /**\n * 2.11 (#481): releases the WebGPU device the view acquired (none with `gpu: \"off\"`, or when `gpuDevice` gave an accelerator,\n * whose device its owner keeps). Later renders run the CPU reference labelled `fallbackReason: \"disposed\"` (`\"auto\"`) or fail\n * with that reason (`\"require\"`). Idempotent.\n */\n dispose(): void;\n /**\n * 2.10 (#447): the key of this request's AHD low-signal correction states, or null when the request has no AHD\n * (`output.demosaic` other than \"ahd\"). Every input of the key is fixed when the request is prepared; two prepared views\n * with the same key read the same states.\n */\n correctionKey(): string | null;\n /**\n * 2.10 (#447): the grid keys of every correction state a render of `view` reads (ascending, whether or not this realm holds\n * them), found by a render of the view's region that records the states instead of computing them. No image is returned;\n * it costs about one render whose states are all held. Fails with an InvalidConfigurationError when the request has no AHD.\n */\n collectCorrectionStates(view: SimulateDisplayViewOptions, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewCorrectionStateKeys>;\n /**\n * 2.10 (#447): computes the correction states of `gridKeys` (from `collectCorrectionStates`, or a share of them) as a render\n * would, stores them in this realm's cache and returns their values, for {@link bindDisplayViewCorrectionStates} in\n * another realm. States this realm holds are read, not computed. Yields and honours `signal` like `render`. Fails with an\n * InvalidConfigurationError when the request has no AHD or a grid key is out of range.\n */\n computeCorrectionStates(gridKeys: Int32Array, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewCorrectionStateSet>;\n}\n/**\n * 2.7 (#387): resolves a {@link simulateDisplayView} request once, without a view, and returns a handle whose `render(view)`\n * renders its views. The setup it does once (request validation, the camera, lens, scene, chart and illuminant, the channel\n * responses through the environment chain, the diffraction kernels, readout moments, demosaic tables and colour matrix) costs\n * about 0.3–1.3 s per call on a 24 MP request; a region costs only its own pixels. Errors in the request are raised here;\n * errors in the view by `render`.\n *\n * 2.11 (#481): `prepareOptions.gpu` chooses the renderer: `\"off\"` (default) is the CPU reference, today's bytes; `\"auto\"` renders\n * on WebGPU when a conforming device is available and the request is supported, else on the CPU, labelled; `\"require\"` fails\n * instead of falling back (`ImageKernelExecutionError`, acquisition failures here, later ones from `render`). `gpuDevice` is a\n * WebGPU entry point or an `ImageKernelAccelerator` whose device the view shares; without it the engine acquires one device\n * for the prepared view (the request's `signal` aborts the acquisition) and `dispose()` releases it. The realm's\n * `setWebGpuEnabled(false)` vetoes both GPU modes (`webgpu-disabled`). See docs/DISPLAY_VIEW.md, \"Rendering on the GPU\".\n * @see docs/QUICK_START.md, \"Display view\".\n */\nexport async function prepareDisplayView(options: SimulateCaptureOptions, prepareOptions?: PrepareDisplayViewOptions): Promise<PreparedDisplayView> {\n const gpuOptions = parsePrepareDisplayViewOptions(prepareOptions);\n let frameWidth = 0, frameHeight = 0;\n const prepared = await runCapture(options, \"display-view\", DISPLAY_VIEW_WITHOUT_VIEW, (context) => {\n frameWidth = context.width; frameHeight = context.height;\n return Promise.resolve(prepareView(context));\n }) as PreparedViewParts;\n // The GPU code is loaded only when a GPU mode asks for it, so bundles on the default stay without it.\n const session: DisplayViewGpuSession | null = gpuOptions.gpu === \"off\" ? null :\n await (await import(\"./display-view-gpu-session.js\")).openDisplayViewGpuSession(gpuOptions, prepared.gpuRequest, (options as { signal?: AbortSignal }).signal);\n /** One call's start times, cancellation (its own signal) and yielding. */\n const runOf = (renderOptions: PreparedDisplayViewRenderOptions | undefined): ViewRun => {\n const started = Date.now(), viewStarted = clockMs();\n const signal = renderOptions === undefined ? undefined : allowKeys(renderOptions, \"render options\", [\"signal\"]).signal as AbortSignal | undefined;\n if (signal !== undefined && (typeof signal !== \"object\" || signal === null || typeof signal.aborted !== \"boolean\")) fail(\"signal must be an AbortSignal.\");\n const checkAbort = (): void => { if (signal?.aborted) fail(\"simulateCapture aborted.\"); };\n checkAbort();\n return { started, viewStarted, checkAbort, yieldControl: createHostYield().yieldControl, signal };\n };\n const correctionOf = (caller: string): DisplayViewCorrectionSetup => prepared.correction ??\n fail(caller + \": the prepared request has no AHD low-signal correction (it applies with output.demosaic \\\"ahd\\\").\");\n const handle: PreparedDisplayView = Object.freeze({\n async render(view: SimulateDisplayViewOptions, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewResult> {\n const run = runOf(renderOptions);\n const parsed = parseDisplayViewOption(view, frameWidth, frameHeight);\n return await prepared.render(parsed, run, undefined, session);\n },\n dispose(): void { session?.dispose(); },\n correctionKey(): string | null { return prepared.correction ? displayViewCorrectionKey(prepared.correction) : null; },\n async collectCorrectionStates(view: SimulateDisplayViewOptions, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewCorrectionStateKeys> {\n const run = runOf(renderOptions), correction = correctionOf(\"collectCorrectionStates\");\n const parsed = parseDisplayViewOption(view, frameWidth, frameHeight);\n return { key: displayViewCorrectionKey(correction)!, gridKeys: await prepared.collect(parsed, run) };\n },\n async computeCorrectionStates(gridKeys: Int32Array, renderOptions?: PreparedDisplayViewRenderOptions): Promise<DisplayViewCorrectionStateSet> {\n const run = runOf(renderOptions), correction = correctionOf(\"computeCorrectionStates\");\n return await computeDisplayViewCorrectionStates({ ...correction, yieldControl: run.yieldControl, checkAbort: run.checkAbort }, gridKeys);\n }\n });\n PREPARED_INTERNALS.set(handle, async (view, renderOptions) => {\n const internals: ViewInternals = {};\n const result = await prepared.render(parseDisplayViewOption(view, frameWidth, frameHeight), runOf(renderOptions), internals, session);\n return { result, internals: internals.value! };\n });\n return handle;\n}\n/** The internal render of each prepared view (the same render as `render`, keeping its renderer's result). */\nconst PREPARED_INTERNALS = new WeakMap<PreparedDisplayView, (view: SimulateDisplayViewOptions, renderOptions?: PreparedDisplayViewRenderOptions) =>\n Promise<{ result: DisplayViewResult; internals: DisplayViewRenderResult }>>();\n/**\n * Internal (not exported from the package): renders a view of a prepared view as `render` does (the same GPU session and labels)\n * and also returns the renderer's noise-free expected linear values and noise standard deviations, whichever renderer ran (#480's\n * GPU producer, `scripts/lib/display-view-gpu-page.mjs`).\n */\nexport async function renderPreparedDisplayViewWithInternals(prepared: PreparedDisplayView, view: SimulateDisplayViewOptions, renderOptions?: PreparedDisplayViewRenderOptions):\n Promise<{ result: DisplayViewResult; internals: DisplayViewRenderResult }> {\n const render = PREPARED_INTERNALS.get(prepared);\n if (!render) fail(\"renderPreparedDisplayViewWithInternals needs a view returned by prepareDisplayView.\");\n return await render(view, renderOptions);\n}\n/**\n * Internal (not exported from the package): the display view plus its noise-free expected linear values and noise standard\n * deviations, for the validation scripts and tests.\n */\nexport async function simulateDisplayViewWithInternals(options: SimulateCaptureOptions, view: SimulateDisplayViewOptions):\n Promise<{ result: DisplayViewResult; internals: DisplayViewRenderResult; signal: DisplayViewExpectedSignal; setup: DisplayViewSetup; signalInput: DisplayViewExpectedSignalInput }> {\n const internals: ViewInternals = {};\n const result = await runCapture(options, \"display-view\", view, (context) => renderDisplayViewResult(context, internals)) as DisplayViewResult;\n return { result, internals: internals.value!, signal: internals.signal!, setup: internals.setup!, signalInput: internals.signalInput! };\n}\n\n/** AHD low-signal correction (display view): draws per flat-neighbourhood state, and the pixel noise (linear light) above which it applies. */\nconst DISPLAY_VIEW_AHD_CORRECTION_DRAWS = 2048, DISPLAY_VIEW_AHD_CORRECTION_THRESHOLD = 0.01;\n\ntype ViewInternals = { value?: DisplayViewRenderResult; signal?: DisplayViewExpectedSignal;\n /** #478: the render's setup and the expected signal's input, for the GPU display view's tests. */\n setup?: DisplayViewSetup; signalInput?: DisplayViewExpectedSignalInput };\n/** What one render of a prepared view needs from its call: its start times, cancellation and yielding. */\ninterface ViewRun { started: number; viewStarted: number; checkAbort: () => void; yieldControl: () => Promise<void>; signal?: AbortSignal | undefined }\ntype RenderPreparedView = (view: ParsedDisplayView, run: ViewRun, viewInternals?: ViewInternals, gpu?: DisplayViewGpuSession | null) => Promise<DisplayViewResult>;\n/**\n * A prepared request: its render, its collect pass (#447: the grid keys of the correction states a view's region reads) and\n * the inputs of its correction states (undefined without AHD).\n */\ninterface PreparedViewParts {\n render: RenderPreparedView;\n collect(view: ParsedDisplayView, run: ViewRun): Promise<Int32Array>;\n correction: DisplayViewCorrectionSetup | undefined;\n /** #481: what a GPU renderer is asked to support. */\n gpuRequest: DisplayViewGpuRequest;\n}\n\n/** Renders the display view of a resolved request (the last step of `runCapture` for \"display-view\"). */\nasync function renderDisplayViewResult(context: DisplayViewRunContext, viewInternals?: ViewInternals): Promise<DisplayViewResult> {\n const viewStarted = clockMs();\n return await prepareView(context).render(context.parsedView!, { started: context.started, viewStarted, checkAbort: context.checkAbort, yieldControl: context.yieldControl }, viewInternals);\n}\n\n/**\n * Internal (#387): the part of a display view that depends only on the request, done once (the portable illuminant, chart and\n * white balance, the channel responses, query offsets, diffraction kernels, readout moments, demosaic tables and colour\n * matrix). The returned function renders one view from it; it keeps no state between renders (each has its own expected-\n * signal caches, lookup count and assumptions), so its results are those of separate calls.\n */\nfunction prepareView(context: DisplayViewRunContext): PreparedViewParts {\n const { ahd, antiAliasing, aspect, axisChannelResponse, boxSamples, buildProvider, callerScene, chart, materialLayers, chartReport, chartSize, diffraction, diffractionPsf, fNumber, focalLengthMm, focusDistanceM, height, highlightMode, exposureGain, illuminanceLux, illuminant, illuminantOption, imagingArea, intentOf, metresPerFrameUnit, noiseSeed, outputOptions, pitch, preset, provider, regimeByChannel, resolvedIso, isoReport, standardExposureDeviationStops, standardExposureIlluminanceLux, greyCardDeviationStops, metering, sceneOption, scenePreset, shutterSeconds, subjectDistanceM, toneCurve, whiteBalanceOption, whiteBalanceState, width, margin, mode, nativeHeight, nativeWidth, sourceSha256 } = context;\n const kelvinInput = context.kelvinWhiteBalanceInput;\n const portableKelvinWhiteBalance = kelvinInput ? (): ResolvedWhiteBalanceState => resolvePortableColorTemperatureWhiteBalance(kelvinInput) : undefined;\n // The engine's illuminant formulas (Planckian, CIE A, daylight locus) evaluated with the portable power and e^x − 1, so\n // the view's radiances, irradiance scale and scene-illuminant white balance have the same bits in every JavaScript\n // engine; they differ from the capture's own by at most a few ulps (docs/DISPLAY_VIEW.md, \"Same bytes in every engine\").\n const viewIlluminant = resolvePortableCaptureIlluminant(illuminantOption), viewIrradianceScale = calculateIlluminantIrradianceScale(viewIlluminant.shape, illuminanceLux);\n const viewProvider = buildProvider(viewIlluminant, viewIrradianceScale);\n const viewWhiteBalanceState = whiteBalanceOption === \"scene-illuminant\" ? sceneIlluminantWhiteBalance(viewIlluminant) : portableKelvinWhiteBalance ? portableKelvinWhiteBalance() : whiteBalanceState;\n // The chart's materials likewise (a step wedge's geometric levels use the portable power); same geometry and order.\n const viewChart = chart ? resolvePortableChartScene({ scene: sceneOption as ChartScene, aspect: chartSize ? chartSize.heightM / chartSize.widthM : aspect }) : undefined;\n if (chart && viewChart!.materials.length !== chart.materials.length) fail(\"simulateDisplayView: the chart's materials could not be resolved portably.\");\n const { electronsPerRadiance, wavelengths, relativePerElectron } = axisChannelResponse(\"simulateDisplayView\");\n const perNode = CHANNELS.map((c) => Float64Array.from(wavelengths, (nm) => electronsPerRadiance[c].get(nm) ?? 0)) as [Float64Array, Float64Array, Float64Array];\n // The tabulated expected signal's input (#394: shared with the capture's tabulated RAW path).\n const sceneMaterials = viewChart ? viewChart.materials : callerScene?.kind === \"material-function\" ? callerScene.materials : undefined;\n // Defocus (#492): the geometric disc on the site lattice, combined with the diffraction kernels in the tables (expected-signal-setup.ts).\n const defocusDisc = context.defocus, defocusKernel = defocusDisc && defocusDisc.diameterSites > 0 ? createDefocusDiscSiteKernel(defocusDisc.diameterSites) : null;\n // The combined radius is at most 32 + 64 = 96 sites (the diffraction and disc caps), as in the capture.\n const diffractionRadius = diffraction ? diffraction.kernelRadiusSamples : 0, combinedRadius = defocusKernel ? diffractionRadius + defocusKernel.radius : diffractionRadius;\n const { offsets, signalInput } = buildExpectedSignalInput({ nativeWidth, nativeHeight, width, wavelengths, perNode, apertureNodes: apertureNodeOffsets(boxSamples), boxSamples,\n antiAliasing, pitch, defocus: defocusKernel, diffraction: diffraction ? { radius: diffraction.kernelRadiusSamples, psf: diffractionPsf!.configuration.psf, profileWavelengths: diffraction.profile.axes.wavelengthNm } : undefined,\n materials: sceneMaterials && provider.chartMaterialAt ? { materialAt: provider.chartMaterialAt,\n list: [...sceneMaterials.map((m, index) => (m.kind === \"neutral\" ? { neutral: m.reflectance } : { radiance: (nm: number): number => viewProvider.materialRadiance!(index, nm) })),\n ...(chartSize ? [{ neutral: chartSize.surroundReflectance }] : [])],\n whiteRadiance: (nm: number): number => viewIrradianceScale * viewIlluminant.shape.evaluate(nm) / Math.PI } : undefined,\n radianceAt: viewProvider.radianceAt, imagingArea, focalLengthMm, focusDistanceM, subjectDistanceM, metresPerFrameUnit, caller: \"simulateDisplayView\" });\n const kernels = signalInput.kernels;\n // Readout moments per channel: normalized value k·e with variance k²·(e + σ_read²) plus the ADC quantization (1/12 code², times d² before a digital gain d).\n // #556: a development exposure push G multiplies the normalized value before the per-site clip at white: k → G·k and the constant variance → G²·(…).\n // Without a push G = 1, and x·1 = x exactly in IEEE 754 arithmetic, so the moments are bit-identical to those without the push.\n const readout = CHANNELS.map((channel): DisplayViewChannelReadout => {\n const { readoutProfile, regimeId } = regimeByChannel[channel];\n const resolved = resolveSensorReadoutRegime({ profile: readoutProfile as Parameters<typeof resolveSensorReadoutRegime>[0][\"profile\"], regimeId });\n const k = relativePerElectron[channel], digitalGain = resolved.regime.adc.digitalGain ?? 1, gain = resolved.regime.systemConversionGainElectronsPerCode.value;\n const codeSpan = digitalGain / (gain * k), read = resolved.combinedReadNoiseRmsElectrons;\n const quantizationCodes = digitalGain * digitalGain / 12 + (digitalGain === 1 ? 0 : 1 / 12);\n return { perElectron: exposureGain * k, darkElectrons: DARK_CURRENT_ELECTRONS_PER_SECOND * shutterSeconds,\n constantVariance: exposureGain * exposureGain * (k * k * read * read + quantizationCodes / (codeSpan * codeSpan)) };\n }) as [DisplayViewChannelReadout, DisplayViewChannelReadout, DisplayViewChannelReadout];\n const phases = bilinearPhaseProfiles(), demosaicTable: { dx: number; dy: number; weight: number }[][][] = [];\n for (const phase of phases) demosaicTable[phase.phaseY * 2 + phase.phaseX] = CHANNELS.map((c) => phase.profile.kernels.find((k) => k.outputChannelId === c)!.contributions\n .map((t) => ({ dx: t.offsetX, dy: t.offsetY, weight: t.weight })));\n const viewIntent = intentOf(viewWhiteBalanceState), viewGains = viewIntent ? [viewIntent.channelGains.red, viewIntent.channelGains.green, viewIntent.channelGains.blue] : null;\n const colour = prepareSensorColorDevelopment(CAMERA_TO_XYZ as unknown as Parameters<typeof prepareSensorColorDevelopment>[0], viewGains, highlightMode);\n const toSrgb = resolveCaptureColorModel().xyzToCameraRgb, m = colour.cameraToXyz;\n const matrix = [0, 1, 2].map((r) => [0, 1, 2].map((c) => toSrgb[r]![0]! * m[0]![c]! + toSrgb[r]![1]! * m[1]![c]! + toSrgb[r]![2]! * m[2]![c]!));\n // Reach of a footprint's pixels into the scene, in sites: the demosaic (1), the largest query offset and the kernel radius.\n const reachSites = (ahd ? 3 : 1) + Math.ceil(Math.max(0, ...offsets.map((o) => Math.max(Math.abs(o.x), Math.abs(o.y))))) + (kernels ? kernels.radius : 0);\n // The inputs of the AHD correction states (fixed here, so the correction key is too; #447).\n const gains = colour.appliedGains as [number, number, number], clipLevel = Math.min(...colour.appliedGains), viewToneCurve = toneCurve as \"identity\" | \"positive-reinhard-per-channel\";\n const ahdCorrection = ahd ? { labMatrix: CAMERA_TO_XYZ.map((row) => row.map((value, c) => value * (viewGains ? viewGains[c]! : 1))), drawsPerState: DISPLAY_VIEW_AHD_CORRECTION_DRAWS,\n thresholdVariance: DISPLAY_VIEW_AHD_CORRECTION_THRESHOLD * DISPLAY_VIEW_AHD_CORRECTION_THRESHOLD } : undefined;\n const ahdCandidates = ahd ? [0, 1, 2, 3].map((p) => ahdCandidateKernels(p % 2, Math.floor(p / 2))) : undefined;\n // #491: a fixed-size chart's placement for the GPU material lookup (the provider's chart-local units cu = u·m/h and the surround beyond the chart).\n const placement = chartSize ? { chartUnitsPerFrameUnit: metresPerFrameUnit / (chartSize.widthM / 2), aspect: chartSize.heightM / chartSize.widthM } : null;\n /** The renderer's setup of one view (with `ahdCollect`, a collect pass), and its expected signal. */\n const setupOf = (v: ParsedDisplayView, viewRegion: { x: number; y: number; width: number; height: number }, { checkAbort, yieldControl }: ViewRun,\n ahdCollect?: Set<number>): { setup: DisplayViewSetup; signal: DisplayViewExpectedSignal } => {\n // The native columns the region's windows span, beyond one window's width: a filled band need not be wider (a speed hint).\n const signal = createDisplayViewExpectedSignal(signalInput, Math.ceil((viewRegion.width + 2) * nativeWidth / v.width));\n return { signal, setup: { frameWidth: width, frameHeight: height, margin, nativeWidth, nativeHeight, viewWidth: v.width, viewHeight: v.height,\n region: viewRegion, samplesPerAxis: v.samplesPerAxis, reachSites, bitDepth: v.bitDepth, seed: noiseSeed, signal, readout, demosaic: demosaicTable,\n ...(ahdCandidates && ahdCorrection ? { candidates: ahdCandidates, ahdCorrection } : {}), ...(ahdCollect ? { ahdCollect } : {}),\n gains, clipLevel, matrix, toneCurve: viewToneCurve, yieldControl, checkAbort, gpu: { signalInput, chart: viewChart ?? null, layers: materialLayers ?? null, placement, ...(defocusKernel ? { defocusRadius: defocusKernel.radius } : {}) } } };\n };\n const correction: DisplayViewCorrectionSetup | undefined = ahdCorrection ? { seed: noiseSeed, readout, gains, clipLevel, matrix, toneCurve: viewToneCurve, ahdCorrection } : undefined;\n const collect = async (v: ParsedDisplayView, run: ViewRun): Promise<Int32Array> => {\n const keys = new Set<number>();\n await renderDisplayView(setupOf(v, v.region ?? { x: 0, y: 0, width: v.width, height: v.height }, run, keys).setup);\n return Int32Array.from(keys).sort();\n };\n // #492: out of focus the view reads the defocus disc (its kernel in signalInput.kernels); the GPU Quality site pass gathers it (step 2c).\n const gpuRequest: DisplayViewGpuRequest = { ahd, defocus: defocusKernel !== null, diffraction: diffraction !== undefined, antiAliasing: antiAliasing !== undefined, boxSamples, toneCurve: viewToneCurve,\n scene: chart ? \"chart\" : materialLayers ? \"material-layers\" : callerScene!.kind };\n const render: RenderPreparedView = async (v, run, viewInternals, gpu) => {\n const { started, viewStarted } = run;\n const assumptions: SimulateCaptureAssumption[] = [...context.assumptions];\n const assume = (id: string, kind: SimulateCaptureAssumption[\"kind\"], value: unknown, explanation: string): void => { assumptions.push({ id, kind, value, explanation }); };\n const viewRegion = v.region ?? { x: 0, y: 0, width: v.width, height: v.height };\n const { setup, signal } = setupOf(v, viewRegion, run);\n // #481: the GPU session renders on the device when it can, else through the CPU reference, and labels which ran.\n const cpu = (): Promise<DisplayViewRenderResult> => renderDisplayView(setup);\n const { rendered, execution }: { rendered: DisplayViewRenderResult; execution: DisplayViewExecution } = gpu ? await gpu.render(setup, run.signal, cpu)\n : { rendered: await cpu(), execution: cpuDisplayViewExecution(\"off\", null, null, null) };\n if (viewInternals) { viewInternals.value = rendered; viewInternals.signal = signal; viewInternals.setup = setup; viewInternals.signalInput = signalInput; }\n const viewMs = clockMs() - viewStarted, scaleX = width / v.width, scaleY = height / v.height;\n assume(\"view.definition\", \"model\", { resampling: \"area-average-linear-light\", width: v.width, height: v.height, frameWidth: width, frameHeight: height, scaleX, scaleY },\n \"The image the full-resolution capture of this request would give after resizing to \" + v.width + \" × \" + v.height + \": each display pixel is the area-weighted mean, in linear light (sRGB samples decoded with the sRGB EOTF), \" +\n \"of the real output pixels its rectangle covers (\" + scaleX + \" × \" + scaleY + \" real pixels), then sRGB-encoded and rounded. The real capture's own samples are rounded to the view's bit depth before averaging.\");\n const uniformSamplesPerAxis = Math.max(1, Math.round(v.samplesPerAxis / 4));\n const siteSentence = \"the expected electrons of the real sites its demosaic reads are exact at the real pitch (the scene sampled at those sites through the pixel aperture, \" +\n \"anti-aliasing filter and diffraction kernels, with the capture's own query arithmetic, so the colour mosaic and its aliasing are the real sensor's), and the per-site clip at white, the highlight clip, the tone curve \" +\n \"and the clip to [0, 1] act on the pixel's own noise distribution, approximated as normal.\";\n // 2.8 (#393): where a footprint holds at most 25 real pixels (and at most K²), every real pixel of it is evaluated once with its exact weight.\n if (rendered.estimation === \"exact-area-mean\") {\n assume(\"view.estimation\", \"model\", { method: \"exact-area-mean-over-real-pixels\", samplesPerAxis: v.samplesPerAxis, realPixelsPerDisplayPixel: scaleX * scaleY,\n evaluatedRealPixels: rendered.sampleCount },\n \"Each display pixel's expected value is the exact area mean of the real pixels its rectangle covers: every real pixel it touches is evaluated once and weighted by its overlap with the rectangle \" +\n \"(w_j / A, summing to 1), so there is no sampling error. This applies because each rectangle holds \" + scaleX * scaleY + \" real pixels (\" + scaleX + \" × \" + scaleY + \"), at most \" + EXACT_AREA_MEAN_MAX_PIXELS + \" and at most K² = \" + v.samplesPerAxis * v.samplesPerAxis + \"; coarser views use a stratified estimate, which costs less there. \" +\n \"For each real pixel \" + siteSentence);\n } else {\n assume(\"view.estimation\", \"model\", { method: \"stratified-monte-carlo-over-real-pixels\", samplesPerAxis: v.samplesPerAxis, uniformSamplesPerAxis,\n detailPixels: rendered.detailPixelCount, uniformPixels: rendered.uniformPixelCount },\n \"Each display pixel's expected value is the mean over K × K strata of its rectangle, one seeded uniformly jittered real pixel in each, so it is unbiased; the error is zero where the rectangle is uniform \" +\n \"and falls as K^-3/2 at an edge. K = \" + v.samplesPerAxis + \" where a fixed pilot grid over the rectangle (widened by the demosaic, filter and kernel reach) or a neighbouring pixel's grid finds more than one scene value, \" +\n \"K = \" + uniformSamplesPerAxis + \" elsewhere. For each sampled pixel \" + siteSentence);\n }\n assume(\"view.noise\", \"model\", { method: \"variance-of-the-area-mean\", distribution: \"normal\" },\n \"Noise of the mean of the real pixels: the covariance of the weighted sum of independent site noises (shot, dark, read and ADC), with the demosaic correlation (B_c = Σ β², in closed form from the rectangle) and the \" +\n \"expected slopes of the clips and the tone curve (Stein's lemma); the variance the linearization misses and the real pixels' output rounding are added per pixel. One correlated normal draw per display pixel, seeded \" +\n \"by sensor.noiseSeed: the same statistics as the resized capture, not the same realization.\");\n assume(\"view.demosaic\", \"model\", ahd ? { capture: \"ahd\", view: \"ahd-candidates-with-low-signal-correction\", correctedPixels: rendered.ahdCorrectedPixelCount,\n correctionDrawsPerState: DISPLAY_VIEW_AHD_CORRECTION_DRAWS, correctionThresholdLinearStd: DISPLAY_VIEW_AHD_CORRECTION_THRESHOLD } : { capture: \"bilinear\", view: \"bilinear\" },\n ahd ? \"AHD is non-linear only in its choice between two linear candidates (green along the rows or the columns, red and blue from colour differences). The view propagates both candidates' exact linear statistics \" +\n \"and averages them. Where a sampled pixel's noise exceeds \" + DISPLAY_VIEW_AHD_CORRECTION_THRESHOLD + \" (linear light), the choice reacts to the noise and shifts the colour, so the pixel adds the mean \" +\n \"difference between the engine's AHD steps and the two candidates on \" + DISPLAY_VIEW_AHD_CORRECTION_DRAWS + \" drawn noisy flat neighbourhoods (Poisson electrons plus read and ADC noise) with its channel means, \" +\n \"computed once per state of a logarithmic grid (8 steps per octave of the channel means) and interpolated trilinearly, a control variate with no per-pixel sampling noise; \" +\n \"the flat-neighbourhood state is an approximation at edges (docs/DISPLAY_VIEW.md, validation).\" :\n \"The bilinear demosaic's linear kernels, exactly.\");\n if (defocusKernel) {\n assume(\"view.defocus\", \"model\", { kernel: diffraction ? \"diffraction-convolved-with-disc\" : \"disc\", defocusKernelRadiusSites: defocusKernel.radius,\n diffractionKernelRadiusSites: diffraction ? diffractionRadius : null, kernelRadiusSites: combinedRadius, scientificStatus: \"approximation\" },\n \"The expected electrons of each real site read the scene on the site lattice through the defocus disc (\" + defocusKernel.diameterSites + \" sites across, a \" + defocusKernel.width + \" × \" +\n defocusKernel.width + \" window), as the capture's object-space convolution does; the estimators then run unchanged on the blurred signal. \" + (diffraction ?\n \"With lens.diffraction each spectral node's kernel is its diffraction kernel convolved with the disc (\" + (2 * combinedRadius + 1) + \" × \" + (2 * combinedRadius + 1) + \" taps): \" +\n \"an approximation, because the PSF of a defocused wave is not the in-focus Airy pattern convolved with a geometric disc.\" :\n \"The disc is the same at every spectral node (geometric optics).\"));\n }\n if (execution.backend === \"webgpu-f32\") {\n assume(\"view.execution\", \"model\", { backend: execution.backend, arithmetic: execution.arithmetic, errorBound: execution.errorBound, adapter: execution.adapter },\n \"Estimated on the GPU: this view was rendered by the WebGPU float32 display-view renderer, a labelled approximation of the float64 CPU reference within the a-priori \" +\n \"error bound reported in diagnostics.fast.execution.errorBound; it is not bit-identical to the reference. The device passed the engine's run-time conformance check first.\");\n }\n assume(\"view.source\", \"model\", { rendering: \"srgb\", format: v.format, ignoredCaptureOutput: [\"format\", \"colorEncoding\", \"bitDepth\", \"gamutMapping\", \"jpegQuantizationStep\", \"dng\", \"metadata\", \"maximumPixels\"].filter((k) => outputOptions[k] !== undefined) },\n \"The view shows the capture's sRGB rendering (its tone curve, white balance and highlight mode); the capture's file-format options do not apply to it.\");\n return Object.freeze({ kind: \"display-view\" as const, label: \"Display view: the full-resolution capture resized to \" + v.width + \" × \" + v.height + \" (estimated); not a capture.\",\n facadeVersion: SIMULATE_CAPTURE_FACADE_VERSION, engineApiVersion: ENGINE_API_VERSION,\n image: { width: viewRegion.width, height: viewRegion.height, format: v.format, samples: rendered.samples },\n view: { width: v.width, height: v.height, frameWidth: width, frameHeight: height, scaleX, scaleY, samplesPerAxis: v.samplesPerAxis, ...(v.region ? { region: { ...v.region } } : {}) },\n exposure: { mode, settings: { fNumber, shutterSeconds, iso: resolvedIso }, ev100: Math.log2(fNumber ** 2 / shutterSeconds), ...isoReport, standardExposureDeviationStops, standardExposureIlluminanceLux, greyCardDeviationStops, metering },\n scene: { sceneId: chart ? \"chart:\" + chart.preset : callerScene!.sceneId, preset: scenePreset, parameters: chart ? chart.parameters : {},\n illuminant: { id: illuminant.id, description: illuminant.description, illuminanceLux }, distanceM: subjectDistanceM,\n framedWidthM: 2 * metresPerFrameUnit, framedHeightM: 2 * metresPerFrameUnit * aspect, ...(chartReport ? { chart: chartReport } : {}), sourceSha256 },\n diagnostics: { sampleCount: rendered.sampleCount, siteEvaluations: rendered.siteCount, sceneLookups: signal.lookups, detailPixelCount: rendered.detailPixelCount,\n uniformPixelCount: rendered.uniformPixelCount, ahdCorrectedPixelCount: rendered.ahdCorrectedPixelCount, timingsMs: { view: viewMs, total: Date.now() - started },\n fast: Object.freeze({ ...context.fastReport, assurance: execution.backend === \"webgpu-f32\" ? \"approximation-with-a-priori-bound\" as const : context.fastReport.assurance, execution }),\n highlight: Object.freeze({ saturatedPixelCount: rendered.saturatedPixelCount, statistic: \"expected-value\" as const }) },\n provenance: { scientificStatus: \"approximation\" as const, cameraPresetId: preset.presetId, cameraPresetVersion: preset.presetVersion, evidence: [...FACADE_EVIDENCE, ...preset.evidence],\n composedContracts: [\"calculateEnvironmentSensorPhotoSignal\", \"resolveSensorReadoutRegime\", \"calculateSiteEffectiveSaturationCode\", ...(diffraction ? [\"createDiffractionLimitedPsfProfile\", \"resolveLensPsfConvolutionKernels\"] : []),\n ...(antiAliasing ? [\"resolveAntiAliasingSpatialKernel\"] : []), \"prepareSensorColorDevelopment\", \"display view estimator\"],\n limitations: [\"Estimated display view of the full-resolution capture: its expected value is a stratified Monte Carlo estimate and its noise is drawn from the variance of the area mean, so it has the resized capture's statistics, not its exact pixels; not a capture and not a measurement.\"] },\n assumptions: Object.freeze(assumptions.map((a) => Object.freeze(a))) });\n };\n return { render, collect, correction, gpuRequest };\n}\n"]}
@@ -101,6 +101,8 @@ export interface DisplayViewQualityGpuResult extends DisplayViewRenderResult {
101
101
  hostRecomputedPixelIndices: Uint32Array;
102
102
  /** The kernel's flag word per display pixel (`DISPLAY_VIEW_QUALITY_FLAG` bits). */
103
103
  pixelFlags: Uint32Array;
104
+ /** #533: display pixels (not flagged) with a real pixel whose saturation the kernel left undecided; their count is the host reference's. */
105
+ highlightRecomputedPixelIndices: Uint32Array;
104
106
  /** Correction states the render computed on the host (new to the store), and the states the table held at the end. */
105
107
  statesComputed: number;
106
108
  statesHeld: number;
@@ -25,7 +25,7 @@
25
25
  * reference, so they are exact. Every stage's wall-clock time is reported (`stageMilliseconds`); on a software adapter it
26
26
  * is not GPU performance.
27
27
  */
28
- import { AHD_KEY_LEVELS, EXACT_AREA_MEAN_MAX_PIXELS, axisSums, computeDisplayViewCorrectionStates, createDisplayViewExpectedSignal, displayViewCorrectionKey, overlaps, renderDisplayView, ahdCandidateKernels } from "../facade/display-view.js";
28
+ import { AHD_KEY_LEVELS, EXACT_AREA_MEAN_MAX_PIXELS, axisSums, computeDisplayViewCorrectionStates, createDisplayViewExpectedSignal, displayViewCorrectionKey, displayViewDecidedSaturation, overlaps, renderDisplayView, ahdCandidateKernels } from "../facade/display-view.js";
29
29
  import { displayViewSignalTables } from "../facade/expected-signal.js";
30
30
  import { resolvePortableChartScene } from "../facade/chart-scenes.js";
31
31
  import { createDisplayViewMaterialModules } from "./display-view-composite-material-module.js";
@@ -36,7 +36,7 @@ import { createHostYieldGate } from "../capture/host-yield-cadence.js";
36
36
  import { createDefocusDiscSiteKernel } from "../optics/defocus-disc-kernel.js";
37
37
  import { ImageKernelExecutionError, WEBGPU_F32_UNIT_ROUNDOFF, webGpuExecution } from "./image-kernel-execution.js";
38
38
  import { BUFFER_USAGE, GpuResourceScope, abortedError, createComputePipeline, linearDispatch, runComputePass } from "./webgpu-runtime.js";
39
- import { DISPLAY_VIEW_QUALITY_AUX, DISPLAY_VIEW_QUALITY_BITMAP_WORDS, DISPLAY_VIEW_QUALITY_CANDIDATE_ENTRIES, DISPLAY_VIEW_QUALITY_CANDIDATE_FLOATS, DISPLAY_VIEW_QUALITY_FLAG, DISPLAY_VIEW_QUALITY_GEOMETRY_STRIDE, DISPLAY_VIEW_QUALITY_GROUP_WORDS, DISPLAY_VIEW_QUALITY_MAXIMUM_PIXELS_PER_AXIS, DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS, DISPLAY_VIEW_QUALITY_PARAM_WORDS, DISPLAY_VIEW_QUALITY_PIXELS_WGSL, DISPLAY_VIEW_QUALITY_SITES_BLOCKED_WGSL, DISPLAY_VIEW_QUALITY_SITES_WGSL, DISPLAY_VIEW_QUALITY_SITE_FLOATS, DISPLAY_VIEW_QUALITY_TAP_WORDS, DISPLAY_VIEW_QUALITY_WORKGROUP_SIZE, assembleDisplayViewQualityLatticeWgsl } from "./wgsl-display-view-quality-kernel.js";
39
+ import { DISPLAY_VIEW_QUALITY_AUX, DISPLAY_VIEW_QUALITY_BITMAP_WORDS, DISPLAY_VIEW_QUALITY_CANDIDATE_ENTRIES, DISPLAY_VIEW_QUALITY_CANDIDATE_FLOATS, DISPLAY_VIEW_QUALITY_FLAG, DISPLAY_VIEW_QUALITY_FLAG_WORDS, DISPLAY_VIEW_QUALITY_GEOMETRY_STRIDE, DISPLAY_VIEW_QUALITY_GROUP_WORDS, DISPLAY_VIEW_QUALITY_MAXIMUM_PIXELS_PER_AXIS, DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS, DISPLAY_VIEW_QUALITY_PARAM_WORDS, DISPLAY_VIEW_QUALITY_PIXELS_WGSL, DISPLAY_VIEW_QUALITY_SITES_BLOCKED_WGSL, DISPLAY_VIEW_QUALITY_SITES_WGSL, DISPLAY_VIEW_QUALITY_SITE_FLOATS, DISPLAY_VIEW_QUALITY_TAP_WORDS, DISPLAY_VIEW_QUALITY_WORKGROUP_SIZE, assembleDisplayViewQualityLatticeWgsl } from "./wgsl-display-view-quality-kernel.js";
40
40
  /** One WGSL rounding of + − × in either direction (W3C WGSL "Floating Point Accuracy"; #471, #487): twice the binary32 unit roundoff. */
41
41
  const E = 2 * WEBGPU_F32_UNIT_ROUNDOFF;
42
42
  /** Every reported bound is doubled: the kernel's running bounds are first order, and their own float32 arithmetic rounds. */
@@ -74,7 +74,7 @@ const WINDOW_SLOTS = (2 * MAXIMUM_REACH + 1) ** 2;
74
74
  */
75
75
  const QUANTIZATION_SLOPE = 6.04, QUANTIZATION_JOIN_JUMP = 2.1e-4, QUANTIZATION_JOIN = 0.0031308;
76
76
  /** Bytes per display pixel in the output buffers (moments plus the flag word). */
77
- const OUTPUT_BYTES_PER_PIXEL = 4 * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS + 4;
77
+ const OUTPUT_BYTES_PER_PIXEL = 4 * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS + 4 * DISPLAY_VIEW_QUALITY_FLAG_WORDS;
78
78
  const SITE_BYTES = 4 * DISPLAY_VIEW_QUALITY_SITE_FLOATS;
79
79
  /**
80
80
  * The low-signal correction states a renderer holds for one correction key, as the GPU table reads them: grid keys ascending
@@ -533,7 +533,7 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
533
533
  const sitesPipeline = blocked ? await pipelines("photivra-display-view-quality-sites-blocked", DISPLAY_VIEW_QUALITY_SITES_BLOCKED_WGSL) :
534
534
  await pipelines("photivra-display-view-quality-sites", DISPLAY_VIEW_QUALITY_SITES_WGSL);
535
535
  const pixelsPipeline = await pipelines("photivra-display-view-quality-pixels", DISPLAY_VIEW_QUALITY_PIXELS_WGSL);
536
- const moments = new Float32Array(pixelCount * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS), pixelFlags = new Uint32Array(pixelCount);
536
+ const moments = new Float32Array(pixelCount * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS), pixelFlags = new Uint32Array(pixelCount), masks = new Uint32Array(2 * pixelCount);
537
537
  const states = input.states ?? new CorrectionStateStore(), correction = setup.ahdCorrection ? correctionSetup(setup) : null;
538
538
  let statesComputed = 0, latticePointsResolved = 0;
539
539
  const scope = new GpuResourceScope(runtime);
@@ -628,7 +628,7 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
628
628
  // Pass 3: display pixels, repeated once when a correction state was missing and has been computed.
629
629
  words[0] = count;
630
630
  const out = band.buffer("photivra-display-view-moments", count * 4 * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS, BUFFER_USAGE.STORAGE | BUFFER_USAGE.COPY_SRC);
631
- const flagBuffer = band.buffer("photivra-display-view-flags", count * 4, BUFFER_USAGE.STORAGE | BUFFER_USAGE.COPY_SRC);
631
+ const flagBuffer = band.buffer("photivra-display-view-flags", count * 4 * DISPLAY_VIEW_QUALITY_FLAG_WORDS, BUFFER_USAGE.STORAGE | BUFFER_USAGE.COPY_SRC);
632
632
  const bitmapBuffer = band.buffer("photivra-display-view-bitmap", 4 * DISPLAY_VIEW_QUALITY_BITMAP_WORDS, BUFFER_USAGE.STORAGE | BUFFER_USAGE.COPY_SRC);
633
633
  for (let attempt = 0;; attempt++) {
634
634
  checkAbort(abort.signal);
@@ -646,13 +646,15 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
646
646
  { binding: 3, resource: { buffer: siteBuffer } }, { binding: 4, resource: { buffer: keysBuffer } }, { binding: 5, resource: { buffer: valuesBuffer } },
647
647
  { binding: 6, resource: { buffer: bitmapBuffer } }, { binding: 7, resource: { buffer: out } }, { binding: 8, resource: { buffer: flagBuffer } }
648
648
  ] });
649
- [data, flagData, bitmapData] = await runComputePass(runtime, pass, pixelsPipeline, pixelGroup, linearDispatch(count, DISPLAY_VIEW_QUALITY_WORKGROUP_SIZE, runtime.maximumWorkgroupsPerDimension), [{ buffer: out, bytes: count * 4 * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS }, { buffer: flagBuffer, bytes: count * 4 }, { buffer: bitmapBuffer, bytes: 4 * DISPLAY_VIEW_QUALITY_BITMAP_WORDS }], abort.signal);
649
+ [data, flagData, bitmapData] = await runComputePass(runtime, pass, pixelsPipeline, pixelGroup, linearDispatch(count, DISPLAY_VIEW_QUALITY_WORKGROUP_SIZE, runtime.maximumWorkgroupsPerDimension), [{ buffer: out, bytes: count * 4 * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS }, { buffer: flagBuffer, bytes: count * 4 * DISPLAY_VIEW_QUALITY_FLAG_WORDS }, { buffer: bitmapBuffer, bytes: 4 * DISPLAY_VIEW_QUALITY_BITMAP_WORDS }], abort.signal);
650
650
  }
651
651
  finally {
652
652
  pass.release();
653
653
  }
654
654
  timings.pixels += now() - t0;
655
- const bandFlags = new Uint32Array(flagData, 0, count);
655
+ const flagWords = new Uint32Array(flagData, 0, count * DISPLAY_VIEW_QUALITY_FLAG_WORDS), bandFlags = new Uint32Array(count);
656
+ for (let i = 0; i < count; i++)
657
+ bandFlags[i] = flagWords[DISPLAY_VIEW_QUALITY_FLAG_WORDS * i];
656
658
  let missing = false;
657
659
  for (let i = 0; i < count && !missing; i++)
658
660
  if ((bandFlags[i] & DISPLAY_VIEW_QUALITY_FLAG.stateMissing) !== 0)
@@ -683,6 +685,10 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
683
685
  }
684
686
  moments.set(new Float32Array(data, 0, count * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS), first * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS);
685
687
  pixelFlags.set(bandFlags, first);
688
+ for (let i = 0; i < count; i++) {
689
+ masks[2 * (first + i)] = flagWords[DISPLAY_VIEW_QUALITY_FLAG_WORDS * i + 1];
690
+ masks[2 * (first + i) + 1] = flagWords[DISPLAY_VIEW_QUALITY_FLAG_WORDS * i + 2];
691
+ }
686
692
  break;
687
693
  }
688
694
  }
@@ -703,11 +709,18 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
703
709
  let t0 = now();
704
710
  const maximum = setup.bitDepth === 8 ? 255 : 65535, step = 1 / maximum;
705
711
  const samples = setup.bitDepth === 8 ? new Uint8Array(pixelCount * 3) : new Uint16Array(pixelCount * 3);
706
- const expected = new Float64Array(pixelCount * 3), noiseStd = new Float64Array(pixelCount * 3);
712
+ const expected = new Float64Array(pixelCount * 3), noiseStd = new Float64Array(pixelCount * 3), saturated = new Float64Array(pixelCount);
707
713
  const meanBound = new Float32Array(pixelCount), varianceBound = new Float32Array(pixelCount);
708
714
  const flagged = [];
709
715
  let largestMean = 0, largestVariance = 0, sampleCount = 0, siteCount = 0, corrected = 0;
710
716
  const counts = new Int32Array(geometry.buffer);
717
+ // #533: each display pixel's saturated-pixel share from the kernel's mask (the reference's arithmetic, exact where it decided).
718
+ const columnOverlaps = Array.from({ length: region.width }, (_, i) => overlaps((region.x + i) * shape.sx, (region.x + i + 1) * shape.sx, setup.frameWidth));
719
+ for (let ry = 0, i = 0; ry < region.height; ry++) {
720
+ const rowOverlaps = overlaps((region.y + ry) * shape.sy, (region.y + ry + 1) * shape.sy, setup.frameHeight);
721
+ for (let rx = 0; rx < region.width; rx++, i++)
722
+ saturated[i] = displayViewDecidedSaturation(columnOverlaps[rx], rowOverlaps, area, masks[2 * i], masks[2 * i + 1]);
723
+ }
711
724
  for (let ry = 0, i = 0; ry < region.height; ry++) {
712
725
  const rowWw = rowSums[ry].ww, ny = counts[(region.width + ry) * stride + 1];
713
726
  for (let rx = 0; rx < region.width; rx++, i++) {
@@ -735,7 +748,30 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
735
748
  timings.finishing = now() - t0;
736
749
  // Flagged display pixels: the reference's own pixels (a region render is byte-identical to the whole view's pixels).
737
750
  t0 = now();
738
- const recomputed = [];
751
+ const recomputed = [], highlights = [];
752
+ // #533: unflagged display pixels with an undecided real pixel take the reference's count only (their samples stay the kernel's).
753
+ const undecided = [], isFlagged = new Uint8Array(pixelCount);
754
+ for (const i of flagged)
755
+ isFlagged[i] = 1;
756
+ for (let i = 0; i < pixelCount; i++)
757
+ if (isFlagged[i] === 0 && (pixelFlags[i] & DISPLAY_VIEW_QUALITY_FLAG.highlightUndecided) !== 0)
758
+ undecided.push(i);
759
+ if (undecided.length > 0 && input.recomputeFlagged !== false) {
760
+ const signal = createDisplayViewExpectedSignal(signalInput);
761
+ for (let r = 0; r < undecided.length;) {
762
+ checkAbort(abort.signal);
763
+ const first = undecided[r], rx = first % region.width, ry = (first - rx) / region.width;
764
+ let run = 1;
765
+ while (r + run < undecided.length && undecided[r + run] === first + run && rx + run < region.width)
766
+ run++;
767
+ const part = await renderDisplayView({ ...setup, signal, region: { x: region.x + rx, y: region.y + ry, width: run, height: 1 } });
768
+ for (let k = 0; k < run; k++) {
769
+ saturated[first + k] = part.saturated[k];
770
+ highlights.push(first + k);
771
+ }
772
+ r += run;
773
+ }
774
+ }
739
775
  if (flagged.length > 0) {
740
776
  if (input.recomputeFlagged === false) {
741
777
  // Without recomputation a flagged pixel keeps the kernel's values where they are finite (its bound then does not hold).
@@ -768,6 +804,7 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
768
804
  samples.set(part.samples, first * 3);
769
805
  expected.set(part.expected, first * 3);
770
806
  noiseStd.set(part.noiseStd, first * 3);
807
+ saturated.set(part.saturated, first);
771
808
  for (let k = 0; k < run; k++) {
772
809
  meanBound[first + k] = 0;
773
810
  varianceBound[first + k] = 0;
@@ -783,11 +820,14 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
783
820
  timings.recompute = now() - t0;
784
821
  const relative = MARGIN * CPU_RELATIVE;
785
822
  const expectedValueBound = { kind: "relative-to-reference", relative, absolute: largestMean };
786
- const uncertain = flagged.length - recomputed.length;
787
- return { samples, expected, noiseStd, sampleCount, siteCount, detailPixelCount: pixelCount, uniformPixelCount: 0, ahdCorrectedPixelCount: corrected, estimation: "exact-area-mean",
823
+ const uncertain = flagged.length - recomputed.length + undecided.length - highlights.length;
824
+ let saturatedPixelCount = 0;
825
+ for (let i = 0; i < pixelCount; i++)
826
+ saturatedPixelCount += saturated[i];
827
+ return { samples, expected, noiseStd, sampleCount, siteCount, detailPixelCount: pixelCount, uniformPixelCount: 0, ahdCorrectedPixelCount: corrected, estimation: "exact-area-mean", saturated, saturatedPixelCount,
788
828
  execution: webGpuExecution(expectedValueBound, uncertain), expectedValueBound, varianceBound: { kind: "relative-to-reference", relative, absolute: largestVariance },
789
829
  expectedValueAbsoluteBound: meanBound, varianceAbsoluteBound: varianceBound, flaggedPixelIndices: Uint32Array.from(flagged), hostRecomputedPixelIndices: Uint32Array.from(recomputed),
790
- pixelFlags, statesComputed, statesHeld: states.size, tapsPerSite: gather.tapCount, blockedSum: blocked, siteSumRelativeBound: floats[50], latticePointsResolved, stageMilliseconds: timings };
830
+ pixelFlags, highlightRecomputedPixelIndices: Uint32Array.from(highlights), statesComputed, statesHeld: states.size, tapsPerSite: gather.tapCount, blockedSum: blocked, siteSumRelativeBound: floats[50], latticePointsResolved, stageMilliseconds: timings };
791
831
  }
792
832
  /**
793
833
  * The GPU setup the material modules read for a Quality render (#491's `createDisplayViewMaterialModules`). The composite module
@@ -909,6 +949,9 @@ async function runQualityConformance(handle, signal, defocus) {
909
949
  if (Math.abs(gpu.samples[i] - reference.samples[i]) > 1)
910
950
  return "component " + i + ": sample " + gpu.samples[i] + " differs from the reference " + reference.samples[i] + " by more than one code.";
911
951
  }
952
+ // #533: the saturated-pixel count is the reference's, bit for bit (the light squares sit at the white clip).
953
+ if (gpu.saturatedPixelCount !== reference.saturatedPixelCount)
954
+ return "the saturated-pixel count " + gpu.saturatedPixelCount + " differs from the reference's " + reference.saturatedPixelCount + ".";
912
955
  return true;
913
956
  }
914
957
  finally {
@@ -991,7 +1034,8 @@ export function createDisplayViewGpuRenderer(runtime, options = {}) {
991
1034
  result = await renderDisplayViewQualityOnGpu(runtime, bandBytes, { setup, signalInput, material, ...(states ? { states } : {}) }, abort, options.yieldControl, source);
992
1035
  }
993
1036
  return { samples: result.samples, expected: result.expected, noiseStd: result.noiseStd, sampleCount: result.sampleCount, siteCount: result.siteCount, detailPixelCount: result.detailPixelCount,
994
- uniformPixelCount: result.uniformPixelCount, ahdCorrectedPixelCount: result.ahdCorrectedPixelCount, estimation: result.estimation, errorBound: result.expectedValueBound,
1037
+ uniformPixelCount: result.uniformPixelCount, ahdCorrectedPixelCount: result.ahdCorrectedPixelCount, estimation: result.estimation, saturated: result.saturated,
1038
+ saturatedPixelCount: result.saturatedPixelCount, errorBound: result.expectedValueBound,
995
1039
  diagnosticUncertaintySampleCount: result.execution.diagnosticUncertaintySampleCount, ...(material.compositeProbe ? { compositeProbe: material.compositeProbe } : {}) };
996
1040
  }
997
1041
  finally {