@photivra/engine 2.21.0 → 2.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +150 -1
- package/CITATION.cff +1 -1
- package/README.md +6 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +11 -0
- package/dist/capture/c2pa-embed.d.ts +116 -0
- package/dist/capture/c2pa-embed.js +493 -0
- package/dist/capture/c2pa-embed.js.map +1 -0
- package/dist/capture/dng-import.d.ts +73 -8
- package/dist/capture/dng-import.js +315 -80
- package/dist/capture/dng-import.js.map +1 -1
- package/dist/capture/dng-opcodes.d.ts +96 -0
- package/dist/capture/dng-opcodes.js +391 -0
- package/dist/capture/dng-opcodes.js.map +1 -0
- package/dist/capture/dng-profile-maps.d.ts +99 -0
- package/dist/capture/dng-profile-maps.js +381 -0
- package/dist/capture/dng-profile-maps.js.map +1 -0
- package/dist/capture/dng-stage-image.d.ts +23 -0
- package/dist/capture/dng-stage-image.js +65 -0
- package/dist/capture/dng-stage-image.js.map +1 -0
- package/dist/capture/jpeg-xl-tiles.d.ts +22 -0
- package/dist/capture/jpeg-xl-tiles.js +151 -0
- package/dist/capture/jpeg-xl-tiles.js.map +1 -0
- package/dist/capture/lossy-jpeg.d.ts +17 -0
- package/dist/capture/lossy-jpeg.js +369 -0
- package/dist/capture/lossy-jpeg.js.map +1 -0
- package/dist/capture/native-raw-development.d.ts +2 -1
- package/dist/capture/native-raw-development.js.map +1 -1
- package/dist/color/neighbor-highlight-reconstruction.d.ts +76 -0
- package/dist/color/neighbor-highlight-reconstruction.js +257 -0
- package/dist/color/neighbor-highlight-reconstruction.js.map +1 -0
- package/dist/color/sensor-color-development.d.ts +5 -0
- package/dist/color/sensor-color-development.js +7 -1
- package/dist/color/sensor-color-development.js.map +1 -1
- package/dist/color/spectral-spikiness.d.ts +11 -0
- package/dist/color/spectral-spikiness.js +23 -0
- package/dist/color/spectral-spikiness.js.map +1 -0
- package/dist/core/execution-error.d.ts +21 -0
- package/dist/core/execution-error.js +12 -0
- package/dist/core/execution-error.js.map +1 -0
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/core/version.js.map +1 -1
- package/dist/facade/catalogue-lens-signal.d.ts +26 -1
- package/dist/facade/catalogue-lens-signal.js +25 -7
- package/dist/facade/catalogue-lens-signal.js.map +1 -1
- package/dist/facade/diffraction-provider.d.ts +1 -1
- package/dist/facade/diffraction-provider.js +4 -4
- package/dist/facade/diffraction-provider.js.map +1 -1
- package/dist/facade/display-view-gpu-session.js +38 -6
- package/dist/facade/display-view-gpu-session.js.map +1 -1
- package/dist/facade/display-view-gpu.d.ts +13 -5
- package/dist/facade/display-view-gpu.js.map +1 -1
- package/dist/facade/display-view-normal.d.ts +15 -0
- package/dist/facade/display-view-normal.js +44 -0
- package/dist/facade/display-view-normal.js.map +1 -0
- package/dist/facade/display-view-rendering.d.ts +102 -0
- package/dist/facade/display-view-rendering.js +633 -0
- package/dist/facade/display-view-rendering.js.map +1 -0
- package/dist/facade/display-view.d.ts +37 -65
- package/dist/facade/display-view.js +147 -476
- package/dist/facade/display-view.js.map +1 -1
- package/dist/facade/expected-signal-setup.js +2 -2
- package/dist/facade/expected-signal-setup.js.map +1 -1
- package/dist/facade/fast-methods.d.ts +1 -1
- package/dist/facade/fast-methods.js +37 -8
- package/dist/facade/fast-methods.js.map +1 -1
- package/dist/facade/generic-lens-capture.d.ts +1 -1
- package/dist/facade/generic-lens-capture.js +1 -1
- package/dist/facade/generic-lens-capture.js.map +1 -1
- package/dist/facade/image-plane.js +41 -10
- package/dist/facade/image-plane.js.map +1 -1
- package/dist/facade/on-demand-kits.d.ts +14 -0
- package/dist/facade/on-demand-kits.js +36 -0
- package/dist/facade/on-demand-kits.js.map +1 -0
- package/dist/facade/opt-in-kit.d.ts +9 -0
- package/dist/facade/opt-in-kit.js +11 -0
- package/dist/facade/opt-in-kit.js.map +1 -0
- package/dist/facade/quality-kit.d.ts +21 -0
- package/dist/facade/quality-kit.js +23 -0
- package/dist/facade/quality-kit.js.map +1 -0
- package/dist/facade/quality-paths.d.ts +22 -0
- package/dist/facade/quality-paths.js +44 -0
- package/dist/facade/quality-paths.js.map +1 -0
- package/dist/facade/scene-radiance.d.ts +18 -2
- package/dist/facade/scene-radiance.js +6 -4
- package/dist/facade/scene-radiance.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +32 -13
- package/dist/facade/simulate-capture.js +162 -69
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.d.ts +10 -12
- package/dist/facade/simulate-display-view.js +57 -48
- package/dist/facade/simulate-display-view.js.map +1 -1
- package/dist/gpu/display-view-gpu-renderer.d.ts +43 -0
- package/dist/gpu/display-view-gpu-renderer.js +134 -0
- package/dist/gpu/display-view-gpu-renderer.js.map +1 -0
- package/dist/gpu/display-view-image-material-module.d.ts +3 -2
- package/dist/gpu/display-view-image-material-module.js +25 -3
- package/dist/gpu/display-view-image-material-module.js.map +1 -1
- package/dist/gpu/display-view-image-quality.d.ts +43 -1
- package/dist/gpu/display-view-image-quality.js +256 -11
- package/dist/gpu/display-view-image-quality.js.map +1 -1
- package/dist/gpu/display-view-quality-gpu.d.ts +13 -64
- package/dist/gpu/display-view-quality-gpu.js +55 -240
- package/dist/gpu/display-view-quality-gpu.js.map +1 -1
- package/dist/gpu/display-view-speed-gpu.d.ts +16 -16
- package/dist/gpu/display-view-speed-gpu.js +62 -19
- package/dist/gpu/display-view-speed-gpu.js.map +1 -1
- package/dist/gpu/image-kernel-accelerator.js +3 -0
- package/dist/gpu/image-kernel-accelerator.js.map +1 -1
- package/dist/gpu/image-kernel-execution.d.ts +2 -13
- package/dist/gpu/image-kernel-execution.js +2 -10
- package/dist/gpu/image-kernel-execution.js.map +1 -1
- package/dist/gpu/wgsl-display-view-coupled-stub.d.ts +13 -0
- package/dist/gpu/wgsl-display-view-coupled-stub.js +29 -0
- package/dist/gpu/wgsl-display-view-coupled-stub.js.map +1 -0
- package/dist/gpu/wgsl-display-view-coupled.d.ts +91 -0
- package/dist/gpu/wgsl-display-view-coupled.js +365 -0
- package/dist/gpu/wgsl-display-view-coupled.js.map +1 -0
- package/dist/gpu/wgsl-display-view-neighbors.d.ts +46 -0
- package/dist/gpu/wgsl-display-view-neighbors.js +114 -0
- package/dist/gpu/wgsl-display-view-neighbors.js.map +1 -0
- package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +6 -9
- package/dist/gpu/wgsl-display-view-quality-kernel.js +113 -113
- package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
- package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +1 -41
- package/dist/gpu/wgsl-display-view-speed-kernel.js +73 -10
- package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
- package/dist/index.d.ts +11 -3
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/output/camera-channel-response.d.ts +50 -0
- package/dist/output/camera-channel-response.js +69 -0
- package/dist/output/camera-channel-response.js.map +1 -0
- package/dist/output/native-capture-sdr.js +5 -2
- package/dist/output/native-capture-sdr.js.map +1 -1
- package/dist/output/sdr-rendering.d.ts +18 -1
- package/dist/output/sdr-rendering.js +39 -2
- package/dist/output/sdr-rendering.js.map +1 -1
- package/dist/sensor/native-sensor-report.d.ts +10 -0
- package/dist/sensor/native-sensor-report.js +16 -0
- package/dist/sensor/native-sensor-report.js.map +1 -0
- package/dist/sensor/sensor-characteristics.d.ts +81 -13
- package/dist/sensor/sensor-characteristics.js +10 -6
- package/dist/sensor/sensor-characteristics.js.map +1 -1
- package/docs/API_REFERENCE.md +117 -4
- package/docs/QUICK_START.md +37 -8
- package/docs/USAGE.md +105 -22
- package/docs/api/capture-c2pa-embed.md +177 -0
- package/docs/api/capture-dng-import.md +86 -10
- package/docs/api/capture-dng-opcodes.md +93 -0
- package/docs/api/capture-dng-profile-maps.md +141 -0
- package/docs/api/capture-dng-stage-image.md +43 -0
- package/docs/api/capture-jpeg-xl-tiles.md +33 -0
- package/docs/api/capture-lossy-jpeg.md +41 -0
- package/docs/api/capture-native-raw-development.md +2 -1
- package/docs/api/core-execution-error.md +43 -0
- package/docs/api/core-version.md +1 -1
- package/docs/api/exports.json +255 -5
- package/docs/api/facade-display-view-gpu.md +5 -2
- package/docs/api/facade-display-view.md +11 -15
- package/docs/api/facade-fast-methods.md +38 -9
- package/docs/api/facade-quality-paths.md +24 -0
- package/docs/api/facade-scene-radiance.md +1 -1
- package/docs/api/facade-simulate-capture.md +24 -7
- package/docs/api/facade-simulate-display-view.md +10 -12
- package/docs/api/gpu-image-kernel-execution.md +0 -36
- package/docs/api/output-camera-channel-response.md +55 -0
- package/docs/api/output-sdr-rendering.md +6 -1
- package/docs/api/sensor-sensor-characteristics.md +54 -2
- package/llms.txt +1 -0
- package/package.json +6 -5
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type DisplayViewGpuRenderer, type DisplayViewGpuRendererFactory, type DisplayViewGpuRequest } from "../facade/display-view-gpu.js";
|
|
2
|
+
import { type WebGpuRuntime } from "./webgpu-runtime.js";
|
|
3
|
+
type YieldControl = ((signal: AbortSignal) => Promise<void>) | undefined;
|
|
4
|
+
type QualityKit = typeof import("./display-view-quality-gpu.js");
|
|
5
|
+
/**
|
|
6
|
+
* #594: loads the Quality host once (a dynamic import, its own chunk in a bundler that splits) and returns it; concurrent calls
|
|
7
|
+
* share one load. A failed load rejects with `ImageKernelExecutionError` reason `quality-code-unavailable` and is not
|
|
8
|
+
* remembered, so the next call (a later Quality render, or `prepareQualityPaths()`) tries again.
|
|
9
|
+
*/
|
|
10
|
+
export declare function prepareDisplayViewQualityGpu(): Promise<QualityKit>;
|
|
11
|
+
/**
|
|
12
|
+
* Internal, for tests: replaces how the Quality host is loaded (null restores the dynamic import) and forgets a loaded one,
|
|
13
|
+
* so a test can make the load fail and then succeed. Returns nothing; the engine never calls it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function setDisplayViewQualityGpuLoader(loader: (() => Promise<QualityKit>) | null): void;
|
|
16
|
+
/**
|
|
17
|
+
* Why the Quality renderer does not support a prepared request (`DisplayViewGpuRenderer.supports`), or true: engine charts and
|
|
18
|
+
* declared `material-layers` scenes (the material modules of `createDisplayViewMaterialModules`, #491), the identity or Reinhard
|
|
19
|
+
* tone curve and at most 64 query offsets (lattice groups). `lens.defocus` out of focus is supported (#492 step 2c: the site pass
|
|
20
|
+
* gathers the disc, or each node's diffraction kernel convolved with it, up to the reference's own caps of radius 64 and 96);
|
|
21
|
+
* whether a view's footprints take the exact area mean, whether the device passes the composite probe, and whether the kernel
|
|
22
|
+
* table fits the device's storage binding limit, is known only per render.
|
|
23
|
+
*/
|
|
24
|
+
export declare function displayViewQualityGpuSupports(request: DisplayViewGpuRequest): true | string;
|
|
25
|
+
/**
|
|
26
|
+
* The display view's GPU renderer on one runtime (#481's `DisplayViewGpuRenderer`): the Speed kernel for requests it covers
|
|
27
|
+
* (no diffraction, no AHD, no defocus disc, at most 16 offsets) and the Quality kernels for the rest (#492: a defocused Speed
|
|
28
|
+
* request too, with its bilinear demosaic). One pipeline cache per device, one set of
|
|
29
|
+
* material modules (#491: chart presets, composite charts, the 2.3 elements and material-layers scenes; `dispose` releases their
|
|
30
|
+
* uploaded scene records). `render` renders the part's region (`setup.gpu`
|
|
31
|
+
* carries the expected signal's input and the chart; a setup without it, a coarse view or a frame the kernels do not cover
|
|
32
|
+
* throws `unsupported-on-backend`), and throws `aborted` and `device-lost` as the accelerator's operations do. The Quality host
|
|
33
|
+
* is loaded on demand (#594, `prepareDisplayViewQualityGpu`).
|
|
34
|
+
*/
|
|
35
|
+
export declare function createDisplayViewGpuRenderer(runtime: WebGpuRuntime, options?: {
|
|
36
|
+
maximumBandBytes?: number;
|
|
37
|
+
yieldControl?: YieldControl;
|
|
38
|
+
}): DisplayViewGpuRenderer;
|
|
39
|
+
/** The factory `prepareDisplayView` creates the renderer with (one per device): the Speed and Quality kernels behind one renderer. */
|
|
40
|
+
export declare const displayViewGpuRendererFactory: DisplayViewGpuRendererFactory;
|
|
41
|
+
/** Registers the combined renderer as the display view's GPU renderer and returns the factory registered before. */
|
|
42
|
+
export declare function registerDisplayViewGpuRenderer(): DisplayViewGpuRendererFactory | null;
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { createDisplayViewMaterialModules } from "./display-view-composite-material-module.js";
|
|
3
|
+
import { setDisplayViewGpuRendererFactory } from "../facade/display-view-gpu.js";
|
|
4
|
+
import { DISPLAY_VIEW_SPEED_CONFORMANCE_CASE, LARGE_DEFOCUS_REASON, sceneToneAndOffsetsReason, displayViewSpeedGpuSupports, displayViewSpeedGpuUnsupportedReason, renderDisplayViewSpeedOnGpu } from "./display-view-speed-gpu.js";
|
|
5
|
+
import { ImageKernelExecutionError } from "./image-kernel-execution.js";
|
|
6
|
+
import { abortedError, createComputePipeline } from "./webgpu-runtime.js";
|
|
7
|
+
/** Largest lattice group count the Quality tables hold (`display-view-quality-gpu.ts`). */
|
|
8
|
+
const QUALITY_MAXIMUM_GROUPS = 64;
|
|
9
|
+
const importQualityKit = () => import("./display-view-quality-gpu.js");
|
|
10
|
+
let loadQualityKit = importQualityKit;
|
|
11
|
+
let qualityKit = null;
|
|
12
|
+
/**
|
|
13
|
+
* #594: loads the Quality host once (a dynamic import, its own chunk in a bundler that splits) and returns it; concurrent calls
|
|
14
|
+
* share one load. A failed load rejects with `ImageKernelExecutionError` reason `quality-code-unavailable` and is not
|
|
15
|
+
* remembered, so the next call (a later Quality render, or `prepareQualityPaths()`) tries again.
|
|
16
|
+
*/
|
|
17
|
+
export function prepareDisplayViewQualityGpu() {
|
|
18
|
+
if (!qualityKit) {
|
|
19
|
+
const pending = Promise.resolve().then(loadQualityKit).catch((error) => {
|
|
20
|
+
if (qualityKit === pending)
|
|
21
|
+
qualityKit = null;
|
|
22
|
+
throw new ImageKernelExecutionError("quality-code-unavailable", "GPU full-quality code did not load: " + String(error));
|
|
23
|
+
});
|
|
24
|
+
qualityKit = pending;
|
|
25
|
+
}
|
|
26
|
+
return qualityKit;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Internal, for tests: replaces how the Quality host is loaded (null restores the dynamic import) and forgets a loaded one,
|
|
30
|
+
* so a test can make the load fail and then succeed. Returns nothing; the engine never calls it.
|
|
31
|
+
*/
|
|
32
|
+
export function setDisplayViewQualityGpuLoader(loader) {
|
|
33
|
+
loadQualityKit = loader ?? importQualityKit;
|
|
34
|
+
qualityKit = null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Why the Quality renderer does not support a prepared request (`DisplayViewGpuRenderer.supports`), or true: engine charts and
|
|
38
|
+
* declared `material-layers` scenes (the material modules of `createDisplayViewMaterialModules`, #491), the identity or Reinhard
|
|
39
|
+
* tone curve and at most 64 query offsets (lattice groups). `lens.defocus` out of focus is supported (#492 step 2c: the site pass
|
|
40
|
+
* gathers the disc, or each node's diffraction kernel convolved with it, up to the reference's own caps of radius 64 and 96);
|
|
41
|
+
* whether a view's footprints take the exact area mean, whether the device passes the composite probe, and whether the kernel
|
|
42
|
+
* table fits the device's storage binding limit, is known only per render.
|
|
43
|
+
*/
|
|
44
|
+
export function displayViewQualityGpuSupports(request) {
|
|
45
|
+
return sceneToneAndOffsetsReason(request, QUALITY_MAXIMUM_GROUPS);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The display view's GPU renderer on one runtime (#481's `DisplayViewGpuRenderer`): the Speed kernel for requests it covers
|
|
49
|
+
* (no diffraction, no AHD, no defocus disc, at most 16 offsets) and the Quality kernels for the rest (#492: a defocused Speed
|
|
50
|
+
* request too, with its bilinear demosaic). One pipeline cache per device, one set of
|
|
51
|
+
* material modules (#491: chart presets, composite charts, the 2.3 elements and material-layers scenes; `dispose` releases their
|
|
52
|
+
* uploaded scene records). `render` renders the part's region (`setup.gpu`
|
|
53
|
+
* carries the expected signal's input and the chart; a setup without it, a coarse view or a frame the kernels do not cover
|
|
54
|
+
* throws `unsupported-on-backend`), and throws `aborted` and `device-lost` as the accelerator's operations do. The Quality host
|
|
55
|
+
* is loaded on demand (#594, `prepareDisplayViewQualityGpu`).
|
|
56
|
+
*/
|
|
57
|
+
export function createDisplayViewGpuRenderer(runtime, options = {}) {
|
|
58
|
+
const pipelines = new Map();
|
|
59
|
+
const bandBytes = options.maximumBandBytes ?? Math.min(64 * 1024 * 1024, runtime.maximumStorageBindingBytes);
|
|
60
|
+
const source = (label, code) => {
|
|
61
|
+
let pending = pipelines.get(label);
|
|
62
|
+
if (!pending) {
|
|
63
|
+
pending = createComputePipeline(runtime, label, code, undefined);
|
|
64
|
+
pipelines.set(label, pending);
|
|
65
|
+
pending.catch(() => pipelines.delete(label));
|
|
66
|
+
}
|
|
67
|
+
return pending;
|
|
68
|
+
};
|
|
69
|
+
// #491: one set of material modules per device for both kernels (the preset module per chart; the composite module, its probe
|
|
70
|
+
// and its uploaded scene records), released by `dispose`.
|
|
71
|
+
const modules = createDisplayViewMaterialModules(runtime, source);
|
|
72
|
+
return {
|
|
73
|
+
id: "photivra-display-view",
|
|
74
|
+
supports(request) {
|
|
75
|
+
if (request.largeDefocus)
|
|
76
|
+
return LARGE_DEFOCUS_REASON;
|
|
77
|
+
// #492: out of focus the expected signal carries the defocus disc as site kernels, which only the Quality site pass gathers;
|
|
78
|
+
// a Speed request then runs the Quality passes with its own bilinear demosaic (one candidate) and finishing.
|
|
79
|
+
if (request.defocus)
|
|
80
|
+
return displayViewQualityGpuSupports(request);
|
|
81
|
+
const speed = displayViewSpeedGpuSupports(request);
|
|
82
|
+
if (speed === true)
|
|
83
|
+
return true;
|
|
84
|
+
return displayViewQualityGpuSupports(request);
|
|
85
|
+
},
|
|
86
|
+
// #594 (owner, 2026-11-10): the Speed case runs before the device's first render; the Quality cases run before the first
|
|
87
|
+
// render that takes the Quality passes, after their code has loaded.
|
|
88
|
+
conformanceCases: [DISPLAY_VIEW_SPEED_CONFORMANCE_CASE],
|
|
89
|
+
onDemandConformanceCases(setup) {
|
|
90
|
+
// The routing of `render` below: a setup the Speed kernel does not cover takes the Quality passes.
|
|
91
|
+
return setup.gpu && displayViewSpeedGpuUnsupportedReason(setup, setup.gpu.signalInput) !== null ? prepareDisplayViewQualityGpu().then((kit) => kit.DISPLAY_VIEW_QUALITY_CONFORMANCE_CASES) : null;
|
|
92
|
+
},
|
|
93
|
+
async render(part) {
|
|
94
|
+
const { setup, signal } = part;
|
|
95
|
+
if (!setup.gpu)
|
|
96
|
+
throw new ImageKernelExecutionError("unsupported-on-backend", "The display-view setup carries no GPU inputs (setup.gpu); use cpu-reference.");
|
|
97
|
+
const abort = new AbortController(), onAbort = () => abort.abort();
|
|
98
|
+
if (signal?.aborted)
|
|
99
|
+
throw abortedError();
|
|
100
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
101
|
+
try {
|
|
102
|
+
const signalInput = setup.gpu.signalInput;
|
|
103
|
+
let result;
|
|
104
|
+
let material;
|
|
105
|
+
if (displayViewSpeedGpuUnsupportedReason(setup, signalInput) === null) {
|
|
106
|
+
material = await modules.moduleFor(setup.gpu, abort.signal);
|
|
107
|
+
result = await renderDisplayViewSpeedOnGpu(runtime, bandBytes, { setup, signalInput, material }, abort, options.yieldControl, source);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
const kit = await prepareDisplayViewQualityGpu();
|
|
111
|
+
// #581: an image-plane print brings its own passes 1 and 2.
|
|
112
|
+
const image = signalInput.scene.image ? await modules.imagePasses(setup.gpu, abort.signal) : undefined;
|
|
113
|
+
material = image ? { id: "image-plane", wgsl: "", bindings: [] } : await kit.qualityMaterialModule(modules, setup.gpu, abort.signal);
|
|
114
|
+
result = await kit.renderDisplayViewQualityOnGpu(runtime, bandBytes, { setup, signalInput, material, ...(image ? { image } : {}) }, abort, options.yieldControl, source);
|
|
115
|
+
}
|
|
116
|
+
return { samples: result.samples, expected: result.expected, noiseStd: result.noiseStd, sampleCount: result.sampleCount, siteCount: result.siteCount, detailPixelCount: result.detailPixelCount,
|
|
117
|
+
uniformPixelCount: result.uniformPixelCount, estimation: result.estimation, saturated: result.saturated,
|
|
118
|
+
saturatedPixelCount: result.saturatedPixelCount, errorBound: result.expectedValueBound,
|
|
119
|
+
diagnosticUncertaintySampleCount: result.execution.diagnosticUncertaintySampleCount, ...(material.compositeProbe ? { compositeProbe: material.compositeProbe } : {}) };
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
signal?.removeEventListener("abort", onAbort);
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
dispose() { modules.release(); }
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/** The factory `prepareDisplayView` creates the renderer with (one per device): the Speed and Quality kernels behind one renderer. */
|
|
129
|
+
export const displayViewGpuRendererFactory = (handle) => createDisplayViewGpuRenderer(handle);
|
|
130
|
+
/** Registers the combined renderer as the display view's GPU renderer and returns the factory registered before. */
|
|
131
|
+
export function registerDisplayViewGpuRenderer() {
|
|
132
|
+
return setDisplayViewGpuRendererFactory(displayViewGpuRendererFactory);
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=display-view-gpu-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"display-view-gpu-renderer.js","sourceRoot":"","sources":["../../src/gpu/display-view-gpu-renderer.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAYtC,OAAO,EAAE,gCAAgC,EAAE,MAAM,6CAA6C,CAAC;AAC/F,OAAO,EAAE,gCAAgC,EAC2D,MAAM,+BAA+B,CAAC;AAC1I,OAAO,EAAE,mCAAmC,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,2BAA2B,EAAE,oCAAoC,EAAE,2BAA2B,EACxJ,MAAM,6BAA6B,CAAC;AACzE,OAAO,EAAE,yBAAyB,EAAiE,MAAM,6BAA6B,CAAC;AACvI,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAsB,MAAM,qBAAqB,CAAC;AAM9F,2FAA2F;AAC3F,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAElC,MAAM,gBAAgB,GAAG,GAAwB,EAAE,CAAC,MAAM,CAAC,+BAA+B,CAAC,CAAC;AAC5F,IAAI,cAAc,GAA8B,gBAAgB,CAAC;AACjE,IAAI,UAAU,GAA+B,IAAI,CAAC;AAClD;;;;GAIG;AACH,MAAM,UAAU,4BAA4B;IAC1C,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YAC9E,IAAI,UAAU,KAAK,OAAO;gBAAE,UAAU,GAAG,IAAI,CAAC;YAC9C,MAAM,IAAI,yBAAyB,CAAC,0BAA0B,EAAE,sCAAsC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1H,CAAC,CAAC,CAAC;QACH,UAAU,GAAG,OAAO,CAAC;IACvB,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AACD;;;GAGG;AACH,MAAM,UAAU,8BAA8B,CAAC,MAA0C;IACvF,cAAc,GAAG,MAAM,IAAI,gBAAgB,CAAC;IAC5C,UAAU,GAAG,IAAI,CAAC;AACpB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,6BAA6B,CAAC,OAA8B;IAC1E,OAAO,yBAAyB,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC;AACpE,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,4BAA4B,CAAC,OAAsB,EAAE,UAAsE,EAAE;IAC3I,MAAM,SAAS,GAAG,IAAI,GAAG,EAAuC,CAAC;IACjE,MAAM,SAAS,GAAG,OAAO,CAAC,gBAAgB,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC7G,MAAM,MAAM,GAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QAC7C,IAAI,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,CAAC,OAAO,EAAE,CAAC;YAAC,OAAO,GAAG,qBAAqB,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;YAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAAC,CAAC;QAChK,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;IACF,8HAA8H;IAC9H,0DAA0D;IAC1D,MAAM,OAAO,GAAG,gCAAgC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAClE,OAAO;QACL,EAAE,EAAE,uBAAuB;QAC3B,QAAQ,CAAC,OAA8B;YACrC,IAAI,OAAO,CAAC,YAAY;gBAAE,OAAO,oBAAoB,CAAC;YACtD,6HAA6H;YAC7H,6GAA6G;YAC7G,IAAI,OAAO,CAAC,OAAO;gBAAE,OAAO,6BAA6B,CAAC,OAAO,CAAC,CAAC;YACnE,MAAM,KAAK,GAAG,2BAA2B,CAAC,OAAO,CAAC,CAAC;YACnD,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAC;YAChC,OAAO,6BAA6B,CAAC,OAAO,CAAC,CAAC;QAChD,CAAC;QACD,yHAAyH;QACzH,qEAAqE;QACrE,gBAAgB,EAAE,CAAC,mCAAmC,CAAC;QACvD,wBAAwB,CAAC,KAAuB;YAC9C,mGAAmG;YACnG,OAAO,KAAK,CAAC,GAAG,IAAI,oCAAoC,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,4BAA4B,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACpM,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,IAAwB;YACnC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,GAAG;gBAAE,MAAM,IAAI,yBAAyB,CAAC,wBAAwB,EAAE,8EAA8E,CAAC,CAAC;YAC9J,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,EAAE,OAAO,GAAG,GAAS,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACzE,IAAI,MAAM,EAAE,OAAO;gBAAE,MAAM,YAAY,EAAE,CAAC;YAC1C,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3D,IAAI,CAAC;gBACH,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC;gBAC1C,IAAI,MAAwH,CAAC;gBAC7H,IAAI,QAAsC,CAAC;gBAC3C,IAAI,oCAAoC,CAAC,KAAK,EAAE,WAAW,CAAC,KAAK,IAAI,EAAE,CAAC;oBACtE,QAAQ,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;oBAC5D,MAAM,GAAG,MAAM,2BAA2B,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;gBACxI,CAAC;qBAAM,CAAC;oBACN,MAAM,GAAG,GAAG,MAAM,4BAA4B,EAAE,CAAC;oBACjD,4DAA4D;oBAC5D,MAAM,KAAK,GAAI,WAAW,CAAC,KAA6B,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;oBAChI,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,qBAAqB,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;oBACrI,MAAM,GAAG,MAAM,GAAG,CAAC,6BAA6B,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;gBAC3K,CAAC;gBACD,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;oBAC7L,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS;oBACvG,mBAAmB,EAAE,MAAM,CAAC,mBAAmB,EAAE,UAAU,EAAE,MAAM,CAAC,kBAAkB;oBACtF,gCAAgC,EAAE,MAAM,CAAC,SAAS,CAAC,gCAAgC,EAAE,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;YAC3K,CAAC;oBAAS,CAAC;gBAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAAC,CAAC;QAC9D,CAAC;QACD,OAAO,KAAW,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;KACvC,CAAC;AACJ,CAAC;AAED,sIAAsI;AACtI,MAAM,CAAC,MAAM,6BAA6B,GAAkC,CAAC,MAAmC,EAAE,EAAE,CAAC,4BAA4B,CAAC,MAAuB,CAAC,CAAC;AAE3K,oHAAoH;AACpH,MAAM,UAAU,8BAA8B;IAC5C,OAAO,gCAAgC,CAAC,6BAA6B,CAAC,CAAC;AACzE,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The display view's GPU renderer (#478, #479, #481): the Speed kernel for the requests it covers and the Quality kernels for the\n * rest, behind one `DisplayViewGpuRenderer`. #594: the Quality host and its WGSL (`display-view-quality-gpu.ts`,\n * `wgsl-display-view-quality-kernel.ts`) load on demand, at the first render that takes the Quality passes, so a page that only\n * renders Speed views never downloads them. That render first runs the Quality kernels' self-check cases (the renderer's\n * `onDemandConformanceCases`); every Speed render runs only the Speed case before the device's first render. The Quality code,\n * its results and its bounds are unchanged; `prepareDisplayViewQualityGpu()` loads it ahead of time.\n */\n\nimport type { DisplayViewRenderResult, DisplayViewSetup } from \"../facade/display-view.js\";\nimport { createDisplayViewMaterialModules } from \"./display-view-composite-material-module.js\";\nimport { setDisplayViewGpuRendererFactory, type DisplayViewGpuConformanceCase, type DisplayViewGpuPart, type DisplayViewGpuRenderOutput, type DisplayViewGpuRenderer,\n type DisplayViewGpuRendererFactory, type DisplayViewGpuRequest, type DisplayViewGpuRuntimeHandle } from \"../facade/display-view-gpu.js\";\nimport { DISPLAY_VIEW_SPEED_CONFORMANCE_CASE, LARGE_DEFOCUS_REASON, sceneToneAndOffsetsReason, displayViewSpeedGpuSupports, displayViewSpeedGpuUnsupportedReason, renderDisplayViewSpeedOnGpu,\n type DisplayViewGpuMaterialModule } from \"./display-view-speed-gpu.js\";\nimport { ImageKernelExecutionError, type ImageKernelExecution, type ImageKernelRelativeErrorBound } from \"./image-kernel-execution.js\";\nimport { abortedError, createComputePipeline, type WebGpuRuntime } from \"./webgpu-runtime.js\";\n\ntype PipelineSource = (label: string, code: string) => Promise<GPUComputePipeline>;\ntype YieldControl = ((signal: AbortSignal) => Promise<void>) | undefined;\ntype QualityKit = typeof import(\"./display-view-quality-gpu.js\");\n\n/** Largest lattice group count the Quality tables hold (`display-view-quality-gpu.ts`). */\nconst QUALITY_MAXIMUM_GROUPS = 64;\n\nconst importQualityKit = (): Promise<QualityKit> => import(\"./display-view-quality-gpu.js\");\nlet loadQualityKit: () => Promise<QualityKit> = importQualityKit;\nlet qualityKit: Promise<QualityKit> | null = null;\n/**\n * #594: loads the Quality host once (a dynamic import, its own chunk in a bundler that splits) and returns it; concurrent calls\n * share one load. A failed load rejects with `ImageKernelExecutionError` reason `quality-code-unavailable` and is not\n * remembered, so the next call (a later Quality render, or `prepareQualityPaths()`) tries again.\n */\nexport function prepareDisplayViewQualityGpu(): Promise<QualityKit> {\n if (!qualityKit) {\n const pending = Promise.resolve().then(loadQualityKit).catch((error: unknown) => {\n if (qualityKit === pending) qualityKit = null;\n throw new ImageKernelExecutionError(\"quality-code-unavailable\", \"GPU full-quality code did not load: \" + String(error));\n });\n qualityKit = pending;\n }\n return qualityKit;\n}\n/**\n * Internal, for tests: replaces how the Quality host is loaded (null restores the dynamic import) and forgets a loaded one,\n * so a test can make the load fail and then succeed. Returns nothing; the engine never calls it.\n */\nexport function setDisplayViewQualityGpuLoader(loader: (() => Promise<QualityKit>) | null): void {\n loadQualityKit = loader ?? importQualityKit;\n qualityKit = null;\n}\n\n/**\n * Why the Quality renderer does not support a prepared request (`DisplayViewGpuRenderer.supports`), or true: engine charts and\n * declared `material-layers` scenes (the material modules of `createDisplayViewMaterialModules`, #491), the identity or Reinhard\n * tone curve and at most 64 query offsets (lattice groups). `lens.defocus` out of focus is supported (#492 step 2c: the site pass\n * gathers the disc, or each node's diffraction kernel convolved with it, up to the reference's own caps of radius 64 and 96);\n * whether a view's footprints take the exact area mean, whether the device passes the composite probe, and whether the kernel\n * table fits the device's storage binding limit, is known only per render.\n */\nexport function displayViewQualityGpuSupports(request: DisplayViewGpuRequest): true | string {\n return sceneToneAndOffsetsReason(request, QUALITY_MAXIMUM_GROUPS);\n}\n\n/**\n * The display view's GPU renderer on one runtime (#481's `DisplayViewGpuRenderer`): the Speed kernel for requests it covers\n * (no diffraction, no AHD, no defocus disc, at most 16 offsets) and the Quality kernels for the rest (#492: a defocused Speed\n * request too, with its bilinear demosaic). One pipeline cache per device, one set of\n * material modules (#491: chart presets, composite charts, the 2.3 elements and material-layers scenes; `dispose` releases their\n * uploaded scene records). `render` renders the part's region (`setup.gpu`\n * carries the expected signal's input and the chart; a setup without it, a coarse view or a frame the kernels do not cover\n * throws `unsupported-on-backend`), and throws `aborted` and `device-lost` as the accelerator's operations do. The Quality host\n * is loaded on demand (#594, `prepareDisplayViewQualityGpu`).\n */\nexport function createDisplayViewGpuRenderer(runtime: WebGpuRuntime, options: { maximumBandBytes?: number; yieldControl?: YieldControl } = {}): DisplayViewGpuRenderer {\n const pipelines = new Map<string, Promise<GPUComputePipeline>>();\n const bandBytes = options.maximumBandBytes ?? Math.min(64 * 1024 * 1024, runtime.maximumStorageBindingBytes);\n const source: PipelineSource = (label, code) => {\n let pending = pipelines.get(label);\n if (!pending) { pending = createComputePipeline(runtime, label, code, undefined); pipelines.set(label, pending); pending.catch(() => pipelines.delete(label)); }\n return pending;\n };\n // #491: one set of material modules per device for both kernels (the preset module per chart; the composite module, its probe\n // and its uploaded scene records), released by `dispose`.\n const modules = createDisplayViewMaterialModules(runtime, source);\n return {\n id: \"photivra-display-view\",\n supports(request: DisplayViewGpuRequest): true | string {\n if (request.largeDefocus) return LARGE_DEFOCUS_REASON;\n // #492: out of focus the expected signal carries the defocus disc as site kernels, which only the Quality site pass gathers;\n // a Speed request then runs the Quality passes with its own bilinear demosaic (one candidate) and finishing.\n if (request.defocus) return displayViewQualityGpuSupports(request);\n const speed = displayViewSpeedGpuSupports(request);\n if (speed === true) return true;\n return displayViewQualityGpuSupports(request);\n },\n // #594 (owner, 2026-11-10): the Speed case runs before the device's first render; the Quality cases run before the first\n // render that takes the Quality passes, after their code has loaded.\n conformanceCases: [DISPLAY_VIEW_SPEED_CONFORMANCE_CASE],\n onDemandConformanceCases(setup: DisplayViewSetup): Promise<readonly DisplayViewGpuConformanceCase[]> | null {\n // The routing of `render` below: a setup the Speed kernel does not cover takes the Quality passes.\n return setup.gpu && displayViewSpeedGpuUnsupportedReason(setup, setup.gpu.signalInput) !== null ? prepareDisplayViewQualityGpu().then((kit) => kit.DISPLAY_VIEW_QUALITY_CONFORMANCE_CASES) : null;\n },\n async render(part: DisplayViewGpuPart): Promise<DisplayViewGpuRenderOutput> {\n const { setup, signal } = part;\n if (!setup.gpu) throw new ImageKernelExecutionError(\"unsupported-on-backend\", \"The display-view setup carries no GPU inputs (setup.gpu); use cpu-reference.\");\n const abort = new AbortController(), onAbort = (): void => abort.abort();\n if (signal?.aborted) throw abortedError();\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n try {\n const signalInput = setup.gpu.signalInput;\n let result: DisplayViewRenderResult & { expectedValueBound: ImageKernelRelativeErrorBound; execution: ImageKernelExecution };\n let material: DisplayViewGpuMaterialModule;\n if (displayViewSpeedGpuUnsupportedReason(setup, signalInput) === null) {\n material = await modules.moduleFor(setup.gpu, abort.signal);\n result = await renderDisplayViewSpeedOnGpu(runtime, bandBytes, { setup, signalInput, material }, abort, options.yieldControl, source);\n } else {\n const kit = await prepareDisplayViewQualityGpu();\n // #581: an image-plane print brings its own passes 1 and 2.\n const image = (signalInput.scene as { image?: unknown }).image ? await modules.imagePasses(setup.gpu, abort.signal) : undefined;\n material = image ? { id: \"image-plane\", wgsl: \"\", bindings: [] } : await kit.qualityMaterialModule(modules, setup.gpu, abort.signal);\n result = await kit.renderDisplayViewQualityOnGpu(runtime, bandBytes, { setup, signalInput, material, ...(image ? { image } : {}) }, abort, options.yieldControl, source);\n }\n return { samples: result.samples, expected: result.expected, noiseStd: result.noiseStd, sampleCount: result.sampleCount, siteCount: result.siteCount, detailPixelCount: result.detailPixelCount,\n uniformPixelCount: result.uniformPixelCount, estimation: result.estimation, saturated: result.saturated,\n saturatedPixelCount: result.saturatedPixelCount, errorBound: result.expectedValueBound,\n diagnosticUncertaintySampleCount: result.execution.diagnosticUncertaintySampleCount, ...(material.compositeProbe ? { compositeProbe: material.compositeProbe } : {}) };\n } finally { signal?.removeEventListener(\"abort\", onAbort); }\n },\n dispose(): void { modules.release(); }\n };\n}\n\n/** The factory `prepareDisplayView` creates the renderer with (one per device): the Speed and Quality kernels behind one renderer. */\nexport const displayViewGpuRendererFactory: DisplayViewGpuRendererFactory = (handle: DisplayViewGpuRuntimeHandle) => createDisplayViewGpuRenderer(handle as WebGpuRuntime);\n\n/** Registers the combined renderer as the display view's GPU renderer and returns the factory registered before. */\nexport function registerDisplayViewGpuRenderer(): DisplayViewGpuRendererFactory | null {\n return setDisplayViewGpuRendererFactory(displayViewGpuRendererFactory);\n}\n"]}
|
|
@@ -34,7 +34,7 @@ import { type WebGpuRuntime } from "./webgpu-runtime.js";
|
|
|
34
34
|
import type { ChartCompositeProductPath } from "./wgsl-chart-composite-kernel.js";
|
|
35
35
|
import type { DisplayViewGpuMaterialModule } from "./display-view-speed-gpu.js";
|
|
36
36
|
import { type DisplayViewGpuSetup } from "../facade/display-view.js";
|
|
37
|
-
import type
|
|
37
|
+
import { type ImagePlaneSignalScene } from "../facade/scene-radiance.js";
|
|
38
38
|
import { type DisplayViewQualityImagePasses } from "./display-view-quality-gpu.js";
|
|
39
39
|
/** The module's id per product path. */
|
|
40
40
|
export declare function imagePlaneMaterialModuleId(path: ChartCompositeProductPath): string;
|
|
@@ -79,7 +79,8 @@ export declare function createDisplayViewImageModules(runtime: WebGpuRuntime, pr
|
|
|
79
79
|
* #581's run-time self-check of the module, run on a device's first photo: a 12 × 8 photo (a color ramp with hard edges, every
|
|
80
80
|
* lattice cell's corner colors among its pixels) printed at 0.8 of the frame's width on the 18 % surround of a 38 × 26 frame shown
|
|
81
81
|
* at 13 × 9, the GPU against `renderDisplayView` within the a-priori bounds, every flagged pixel recomputed: the Speed kernel with
|
|
82
|
-
* the 2 × 2 box, then the Quality passes with the four-spot filter's 16 offsets and synthetic radius-1 kernels at three nodes
|
|
82
|
+
* the 2 × 2 box, then the Quality passes with the four-spot filter's 16 offsets and synthetic radius-1 kernels at three nodes, and
|
|
83
|
+
* (#597) the same passes under mixed light (a three-source gradient with a hard edge and a point source).
|
|
83
84
|
* A device that fails the double-float32 probe refuses photos (unsupported-on-backend, as composite charts), so the check passes
|
|
84
85
|
* there without keeping the device's charts off the GPU.
|
|
85
86
|
*/
|
|
@@ -35,6 +35,8 @@ import { BUFFER_USAGE, GpuResourceScope } from "./webgpu-runtime.js";
|
|
|
35
35
|
import { dwSplit } from "./chart-composite-gpu.js";
|
|
36
36
|
import { displayViewModuleCommonWgsl, displayViewLatticeConstants, LATTICE_BINDINGS_WGSL, LATTICE_POINT_WGSL } from "./display-view-composite-material-module.js";
|
|
37
37
|
import { renderDisplayView } from "../facade/display-view.js";
|
|
38
|
+
import { resolveCaptureIlluminant } from "../facade/scene-radiance.js";
|
|
39
|
+
import { resolveMixedIllumination } from "../facade/mixed-illumination.js";
|
|
38
40
|
import { imagePlaneSupport } from "../facade/image-plane-support.js";
|
|
39
41
|
import { CONFORMANCE_FRAME, conformanceChannelAt, conformanceResponses, conformanceSetup, conformanceVerdict, renderDisplayViewSpeedOnGpu, withConformanceAbort } from "./display-view-speed-gpu.js";
|
|
40
42
|
import { renderDisplayViewQualityOnGpu } from "./display-view-quality-gpu.js";
|
|
@@ -275,7 +277,8 @@ export function createDisplayViewImageModules(runtime, probe) {
|
|
|
275
277
|
* #581's run-time self-check of the module, run on a device's first photo: a 12 × 8 photo (a color ramp with hard edges, every
|
|
276
278
|
* lattice cell's corner colors among its pixels) printed at 0.8 of the frame's width on the 18 % surround of a 38 × 26 frame shown
|
|
277
279
|
* at 13 × 9, the GPU against `renderDisplayView` within the a-priori bounds, every flagged pixel recomputed: the Speed kernel with
|
|
278
|
-
* the 2 × 2 box, then the Quality passes with the four-spot filter's 16 offsets and synthetic radius-1 kernels at three nodes
|
|
280
|
+
* the 2 × 2 box, then the Quality passes with the four-spot filter's 16 offsets and synthetic radius-1 kernels at three nodes, and
|
|
281
|
+
* (#597) the same passes under mixed light (a three-source gradient with a hard edge and a point source).
|
|
279
282
|
* A device that fails the double-float32 probe refuses photos (unsupported-on-backend, as composite charts), so the check passes
|
|
280
283
|
* there without keeping the device's charts off the GPU.
|
|
281
284
|
*/
|
|
@@ -310,7 +313,21 @@ export async function runImagePlaneConformance(handle, signal) {
|
|
|
310
313
|
const qualityInput = { nativeWidth, nativeHeight, outputWidth: frameWidth, wavelengthsNm: nodes, electronsPerRadiance: A, offsets: qualityOffsets,
|
|
311
314
|
kernels: { radius: 1, perNode: [kernel(0.6), kernel(0.7), kernel(0.8)] }, scene: printScene, channelAt: conformanceChannelAt };
|
|
312
315
|
const quality = conformanceSetup(qualityInput, readout, 582, 5, signal, { gpu: { signalInput: qualityInput, chart: null, placement } });
|
|
313
|
-
|
|
316
|
+
// #597: the same Quality case under mixed light: a gradient of three sources with a hard edge (equal stops) across the print, and a
|
|
317
|
+
// point source over its upper left, the reference's irradiance from the same parts in float64.
|
|
318
|
+
const day = { kind: "planckian", temperatureKelvin: 6500 }, lamp = { kind: "cie-a" };
|
|
319
|
+
const light = resolveMixedIllumination({ sources: [{ illuminant: day, illuminanceLux: 1.2e5 }, { illuminant: lamp, illuminanceLux: 8e4 }, { illuminant: day, illuminanceLux: 3e4 }],
|
|
320
|
+
blend: { kind: "linear-gradient", from: { u: -0.9, v: 0.1 }, to: { u: 0.8, v: -0.2 }, stops: [0, 0.45, 0.45] },
|
|
321
|
+
points: [{ illuminant: lamp, position: { xM: -0.3, yM: 0.2, heightM: 0.35 }, intensity: { illuminanceLux: 6e4, distanceM: 0.35 } }] }, resolveCaptureIlluminant);
|
|
322
|
+
// The print's half width is 1 m here (print-local units are metres), so the point sources read the print-local point.
|
|
323
|
+
const litIrradiance = (cu, cv, nm) => light.irradianceAt(cu, cv, cu, cv, nm);
|
|
324
|
+
const litRadianceAt = (u, v, nm) => {
|
|
325
|
+
const cu = u * k, cv = v * k;
|
|
326
|
+
return (Math.abs(cu) <= 1 && Math.abs(cv) <= aspect ? scene.reflectanceAt(cu, cv, nm) : surround) * litIrradiance(cu, cv, nm) / Math.PI;
|
|
327
|
+
};
|
|
328
|
+
const litInput = { ...qualityInput, scene: scene.signalScene(nodes, A, white, litRadianceAt, k, 1, surround, light) };
|
|
329
|
+
const lit = conformanceSetup(litInput, readout, 597, 5, signal, { gpu: { signalInput: litInput, chart: null, placement } });
|
|
330
|
+
const [speedReference, qualityReference, litReference] = [await renderDisplayView(speed), await renderDisplayView(quality), await renderDisplayView(lit)];
|
|
314
331
|
const images = createDisplayViewImageModules(runtime, (s) => probeChartCompositeDevice(runtime, (label, code) => createComputePipeline(runtime, label, code, s), s));
|
|
315
332
|
try {
|
|
316
333
|
return await withConformanceAbort(runtime, signal, async (abort, pipelines) => {
|
|
@@ -329,7 +346,12 @@ export async function runImagePlaneConformance(handle, signal) {
|
|
|
329
346
|
const gpu = await renderDisplayViewQualityOnGpu(runtime, 1 << 20, { setup: quality, signalInput: qualityInput, material: { id: "image-plane", wgsl: "", bindings: [] },
|
|
330
347
|
image: imagePlaneQualityPasses(runtime, quality.gpu, path) }, abort, undefined, pipelines);
|
|
331
348
|
const qualityVerdict = conformanceVerdict(qualityReference, gpu);
|
|
332
|
-
|
|
349
|
+
if (qualityVerdict !== true)
|
|
350
|
+
return "Quality: " + qualityVerdict;
|
|
351
|
+
const litGpu = await renderDisplayViewQualityOnGpu(runtime, 1 << 20, { setup: lit, signalInput: litInput, material: { id: "image-plane", wgsl: "", bindings: [] },
|
|
352
|
+
image: imagePlaneQualityPasses(runtime, lit.gpu, path) }, abort, undefined, pipelines);
|
|
353
|
+
const litVerdict = conformanceVerdict(litReference, litGpu);
|
|
354
|
+
return litVerdict === true ? true : "Quality under mixed light: " + litVerdict;
|
|
333
355
|
});
|
|
334
356
|
}
|
|
335
357
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"display-view-image-material-module.js","sourceRoot":"","sources":["../../src/gpu/display-view-image-material-module.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The image-plane module of the GPU display view (#581): the Speed kernel's `scene_value` (the seam of #478 and #491,\n * `DisplayViewGpuMaterialModule`) for an image-plane print, so that a photo renders on the device like a chart.\n *\n * **What the reference computes** at a query point (expected-signal.ts, the direct path's `signalAt`): the print-local point\n * cu = u·m/h, cv = v·m/h (outside |cu| ≤ 1, |cv| ≤ aspect the surround: its reflectance times the neutral signal N_c); the\n * pixel coordinates X = (cu + 1)·W/2, Y = (aspect − cv)·H/(2·aspect); then the bilinear weights of the four nearest pixel\n * centers (clamped to the edge) times each pixel's channel signal S_j,c = Σ_n A_c(λ_n)·ρ_j(λ_n)·W_n, integrated from the pixel's\n * reconstructed spectrum ρ_j (its cell's eight node spectra blended, then the paper; `ResolvedImagePlaneScene.pixelSignals`), or\n * the nearest pixel's. No per-channel values of the lattice nodes are formed.\n *\n * **On the device.** The host computes every pixel's S_j,c in float64 and rounds it once to float32 (3 values per pixel). When\n * they fit one storage binding they are uploaded once per scene and kept on the device while the renderer lives; otherwise each\n * band of a render builds and uploads only its rows. Either way they are built and written 4 MiB of rows at a time, so the host\n * never holds more than that of S (owner decision 2026-11-09; the bytes are those of the whole array). The module recovers the exact lattice point from the\n * kernel's float32 point as the composite module does (`LATTICE_POINT_WGSL`, about 2⁻⁴⁶ relative), forms cu, cv, X and Y\n * in double-float32 and decides the print's edge in the composite kernel's bound arithmetic (a point within its bound of the\n * edge is flagged: the display pixel is recomputed on the host). Per axis it splits s = X − ½ into its integer part n and\n * fraction f exactly (double-float32), rounds the smaller of f and 1 − f once to float32 and forms the other as 1 minus it, so\n * each weight carries at most 2E relative error (E = 2⁻²³) besides the point's own error. The point's error moves weight\n * between neighbors: with δ the bound of |X_gpu − X_ref| in pixels (4·(2⁻⁴⁰·(|X| + 1)) + 4·10⁻¹⁴·W/2·k: the recovery, the\n * double-float32 steps and the reference's own float64 rounding of its query point, generously), the value moves by at most\n * (δx + δy)·2·max S, and the point is flagged when that exceeds E times the value. So an unflagged value carries a relative\n * error only: S's rounding 1, the weights 2 + 2, the two products and two sums 4, the flag's budget 1, that is 10 roundings\n * beyond the table lookup's one (`extraSiteRoundings`), added to the Speed kernel's chains (docs/WEBGPU.md, \"Display view (Speed)\").\n * `nearest` takes the pixel under the point, flagging a point within its bound of a pixel edge (`bfloor`). All S are\n * non-negative (non-negative responses, illuminant and spectra), so the weighted sums need no cancellation term.\n *\n * The surround's three channel signals, integrated from its spectrum (its reflectance times the white radiance at each node) like\n * a pixel's, are the kernel's binding 3 (`spectral_table`, which this module does not otherwise use).\n */\n\nimport { ImageKernelExecutionError, type ChartCompositeProbeRecord } from \"./image-kernel-execution.js\";\nimport { BUFFER_USAGE, GpuResourceScope, type WebGpuRuntime } from \"./webgpu-runtime.js\";\nimport { dwSplit } from \"./chart-composite-gpu.js\";\nimport type { ChartCompositeProductPath } from \"./wgsl-chart-composite-kernel.js\";\nimport { displayViewModuleCommonWgsl, displayViewLatticeConstants, LATTICE_BINDINGS_WGSL, LATTICE_POINT_WGSL } from \"./display-view-composite-material-module.js\";\nimport type { DisplayViewGpuMaterialModule } from \"./display-view-speed-gpu.js\";\nimport { renderDisplayView, type DisplayViewGpuSetup } from \"../facade/display-view.js\";\nimport type { DisplayViewExpectedSignalInput } from \"../facade/expected-signal.js\";\nimport type { ImagePlaneSignalScene } from \"../facade/scene-radiance.js\";\nimport { imagePlaneSupport } from \"../facade/image-plane-support.js\";\nimport { CONFORMANCE_FRAME, conformanceChannelAt, conformanceResponses, conformanceSetup, conformanceVerdict, renderDisplayViewSpeedOnGpu, withConformanceAbort } from \"./display-view-speed-gpu.js\";\nimport { renderDisplayViewQualityOnGpu, type DisplayViewQualityImagePasses } from \"./display-view-quality-gpu.js\";\nimport { imagePlaneQualityPasses } from \"./display-view-image-quality.js\";\nimport { ChartCompositeProbeError, probeChartCompositeDevice } from \"./chart-composite-gpu.js\";\nimport { createComputePipeline } from \"./webgpu-runtime.js\";\n\n/** The module's id per product path. */\nexport function imagePlaneMaterialModuleId(path: ChartCompositeProductPath): string { return path === \"dekker\" ? \"image-plane\" : \"image-plane-fma\"; }\n/** Roundings of the module's value beyond the table lookup's one (see the module comment). */\nexport const IMAGE_PLANE_EXTRA_SITE_ROUNDINGS = 10;\n/** Layout of the photo uniform (float32 / u32 words, 64 bytes). */\nexport const IMAGE_PLANE_PARAMS = /* @__PURE__ */ Object.freeze({ width: 0, height: 1, nearest: 2, row0: 3, halfWHi: 4, halfWLo: 5, halfHHi: 6, halfHLo: 7, aspectHi: 8, aspectLo: 9,\n slackX: 10, slackY: 11, words: 16 });\n/** Table values above this are outside the float32 domain. */\nconst FLOAT32_SAFE_MAGNITUDE = 2 ** 120;\n/** Host bytes of pixel signals built per write (whole uploads and bands). */\nconst UPLOAD_CHUNK_BYTES = 4 << 20;\n/** Scenes whose pixel signals stay uploaded per renderer. */\nconst KEPT_SCENES = 2;\n\n/** The module's WGSL with one product path (see the module comment). */\nexport function imagePlaneMaterialWgsl(path: ChartCompositeProductPath = \"dekker\"): string {\n return `${displayViewModuleCommonWgsl(path)}\n@group(1) @binding(0) var<storage, read> photo_signal: array<f32>;\nstruct PhotoParams {\n width: u32, height: u32, nearest: u32, row0: u32,\n half_w_hi: f32, half_w_lo: f32, half_h_hi: f32, half_h_lo: f32,\n aspect_hi: f32, aspect_lo: f32, slack_x: f32, slack_y: f32,\n pad1: f32, pad2: f32, pad3: f32, pad4: f32,\n};\n@group(1) @binding(1) var<uniform> photo: PhotoParams;\n${LATTICE_BINDINGS_WGSL}\n${LATTICE_POINT_WGSL}\n// The point's error bound in pixels along one axis (see the module comment).\nfn pixel_slack(x: D, slack: f32) -> f32 { return 4.0 * (DW * (abs(x.h) + 1.0)) + 4.0 * slack; }\n// One axis of the bilinear weights: the pixel pair (clamped to the edge) and the weights of s = X − 1/2.\nstruct Axis { i0: u32, i1: u32, w0: f32, w1: f32 }\nfn bilinear_axis(s: D, n: u32) -> Axis {\n var f0 = floor(s.h);\n if (f0 == s.h && s.l < 0.0) { f0 = f0 - 1.0; }\n let frac = d_sub(s, D(f0, 0.0));\n let comp = d_sub(D(ob(f0 + 1.0), 0.0), s);\n var w0 = 0.0; var w1 = 0.0;\n if (frac.h <= 0.5) { w1 = ob(frac.h + frac.l); w0 = ob(1.0 - w1); } else { w0 = ob(comp.h + comp.l); w1 = ob(1.0 - w0); }\n let last = i32(n) - 1;\n return Axis(u32(clamp(i32(f0), 0, last)), u32(clamp(i32(f0) + 1, 0, last)), w0, w1);\n}\nfn photo_at(i: u32, j: u32, c: u32) -> f32 { return photo_signal[((j - photo.row0) * photo.width + i) * 3u + c]; }\nfn scene_value(p: vec2<f32>, c: u32) -> f32 {\n let k = D(lattice.chart_k_hi, lattice.chart_k_lo);\n let u = d_mul(lattice_point(p.x, D(lattice.scale_u_hi, lattice.scale_u_lo), 0u), k);\n let v = d_mul(lattice_point(p.y, D(lattice.scale_v_hi, lattice.scale_v_lo), 1u), k);\n let aspect = D(photo.aspect_hi, photo.aspect_lo);\n if (!(le(babs(bd(u)), bx(1.0)) && le(babs(bd(v)), bd(aspect)))) { return spectral_table[c]; }\n let x = d_mul(d_add(u, D(1.0, 0.0)), D(photo.half_w_hi, photo.half_w_lo));\n let y = d_mul(d_sub(aspect, v), D(photo.half_h_hi, photo.half_h_lo));\n if (photo.nearest != 0u) {\n let last_x = f32(photo.width - 1u);\n let last_y = f32(photo.height - 1u);\n let i = u32(clamp(bfloor(bd(x), 1.0, last_x), 0.0, last_x));\n let j = u32(clamp(bfloor(bd(y), 1.0, last_y), 0.0, last_y));\n return photo_at(i, j, c);\n }\n let ax = bilinear_axis(d_sub(x, D(0.5, 0.0)), photo.width);\n let ay = bilinear_axis(d_sub(y, D(0.5, 0.0)), photo.height);\n let s00 = photo_at(ax.i0, ay.i0, c);\n let s10 = photo_at(ax.i1, ay.i0, c);\n let s01 = photo_at(ax.i0, ay.i1, c);\n let s11 = photo_at(ax.i1, ay.i1, c);\n let value = ob(ob(ay.w0 * ob(ob(ax.w0 * s00) + ob(ax.w1 * s10))) + ob(ay.w1 * ob(ob(ax.w0 * s01) + ob(ax.w1 * s11))));\n let largest = max(max(s00, s10), max(s01, s11));\n let moved = (pixel_slack(x, photo.slack_x) + pixel_slack(y, photo.slack_y)) * 2.0 * largest;\n if (!(moved <= E * value)) { material_uncertain = true; }\n return value;\n}\n`;\n}\n\n/** The image-plane print behind a GPU setup's expected signal (`ImagePlaneSignalScene.image`), or undefined. */\nexport function imagePlaneOf(gpu: DisplayViewGpuSetup): ImagePlaneSignalScene[\"image\"] | undefined {\n return (gpu.signalInput.scene as { image?: ImagePlaneSignalScene[\"image\"] }).image;\n}\n/** The pixel signals of a scene on the device (per renderer), keyed by the signal scene's image record. */\ninterface UploadedImage { key: object; scope: GpuResourceScope; buffer: GPUBuffer; surround: Float32Array<ArrayBuffer> }\n\n/** The image-plane modules of one display-view renderer: `moduleFor` builds the setup's module (its uploads kept), `release` frees them. */\nexport interface DisplayViewImageModules {\n /** The setup's module; the first call on a runtime runs the module's self-check (`runImagePlaneConformance`) and refuses the device if it fails. */\n moduleFor(gpu: DisplayViewGpuSetup, signal: AbortSignal): Promise<DisplayViewGpuMaterialModule>;\n /** The setup's module without the self-check (the self-check itself uses it). */\n build(gpu: DisplayViewGpuSetup, path: ChartCompositeProductPath): DisplayViewGpuMaterialModule;\n /** #581: the print's Quality passes 1 and 2 (src/gpu/display-view-image-quality.ts), after the same self-check. */\n qualityPasses(gpu: DisplayViewGpuSetup, signal: AbortSignal): Promise<DisplayViewQualityImagePasses>;\n release(): void;\n}\n\n/**\n * The image-plane modules of a renderer; `probe` is the composite module's device probe (single flight), whose double-word product\n * path the module's double-float32 takes.\n */\nexport function createDisplayViewImageModules(runtime: WebGpuRuntime, probe: (signal: AbortSignal) => Promise<ChartCompositeProbeRecord>): DisplayViewImageModules {\n const uploads: UploadedImage[] = [], wgsl = new Map<ChartCompositeProductPath, string>();\n // Pixel rows [j0, j1)'s channel signals, built on demand so that the host holds one chunk or band (#581): each pixel's signals\n // integrated from its reconstructed spectrum (`pixelSignals`, the reference's own float64 values), rounded once.\n const pixel = new Float64Array(3);\n const rowsOf = (image: ImagePlaneSignalScene[\"image\"], j0: number, j1: number): Float32Array<ArrayBuffer> => {\n const { scene, nodes } = image, values = new Float32Array((j1 - j0) * scene.width * 3);\n for (let j = j0 * scene.width, o = 0; j < j1 * scene.width; j++) {\n scene.pixelSignals(j, nodes, pixel, 0);\n for (let c = 0; c < 3; c++) {\n const value = pixel[c]!;\n if (!(value >= 0 && value <= FLOAT32_SAFE_MAGNITUDE)) throw new ImageKernelExecutionError(\"unsupported-float32-domain\", \"A pixel's channel signal is outside the float32 domain.\");\n values[o++] = value;\n }\n }\n return values;\n };\n // Rows [a, b)'s signals written to `buffer` (whose first row is `base`), built UPLOAD_CHUNK_BYTES of rows at a time.\n const fill = (buffer: GPUBuffer, image: ImagePlaneSignalScene[\"image\"], a: number, b: number, base: number): void => {\n const rowBytes = image.scene.width * 12, chunk = Math.max(1, Math.floor(UPLOAD_CHUNK_BYTES / rowBytes));\n for (let j = a; j < b; j += chunk) { const rows = rowsOf(image, j, Math.min(b, j + chunk)); runtime.device.queue.writeBuffer(buffer, (j - base) * rowBytes, rows.buffer, 0, rows.byteLength); }\n };\n const rowsBuffer = (scope: GpuResourceScope, label: string, image: ImagePlaneSignalScene[\"image\"], j0: number, j1: number): GPUBuffer => {\n const buffer = scope.buffer(label, (j1 - j0) * image.scene.width * 12, BUFFER_USAGE.STORAGE | BUFFER_USAGE.COPY_DST);\n fill(buffer, image, j0, j1, j0);\n return buffer;\n };\n // The latest band's rows stay on the device until the next band: the rows the two share are copied there on the device, and\n // only the others are built on the host (the same bytes; the host still holds one chunk at most).\n let lastBand: { image: object; j0: number; j1: number; scope: GpuResourceScope; buffer: GPUBuffer } | null = null;\n const bandBuffer = (image: ImagePlaneSignalScene[\"image\"], j0: number, j1: number): GPUBuffer => {\n const rowBytes = image.scene.width * 12, scope = new GpuResourceScope(runtime), last = lastBand?.image === image ? lastBand : null;\n try {\n const buffer = scope.buffer(\"photivra-display-view-image-signal-band\", (j1 - j0) * rowBytes, BUFFER_USAGE.STORAGE | BUFFER_USAGE.COPY_DST | BUFFER_USAGE.COPY_SRC);\n const o0 = last ? Math.max(j0, last.j0) : j0, o1 = last ? Math.min(j1, last.j1) : j0;\n if (o1 > o0) {\n const encoder = runtime.device.createCommandEncoder({ label: \"photivra-display-view-image-band-rows\" });\n encoder.copyBufferToBuffer(last!.buffer, (o0 - last!.j0) * rowBytes, buffer, (o0 - j0) * rowBytes, (o1 - o0) * rowBytes);\n runtime.device.queue.submit([encoder.finish()]);\n fill(buffer, image, j0, o0, j0); fill(buffer, image, o1, j1, j0);\n } else fill(buffer, image, j0, j1, j0);\n lastBand?.scope.release();\n lastBand = { image, j0, j1, scope, buffer };\n return buffer;\n } catch (error) { scope.release(); throw error; }\n };\n const upload = (image: ImagePlaneSignalScene[\"image\"]): UploadedImage => {\n const key = image as object, index = uploads.findIndex((e) => e.key === key);\n if (index >= 0) { const [entry] = uploads.splice(index, 1); uploads.push(entry!); return entry!; }\n const scope = new GpuResourceScope(runtime);\n let buffer: GPUBuffer;\n try { buffer = rowsBuffer(scope, \"photivra-display-view-image-signal\", image, 0, image.scene.height); } catch (error) { scope.release(); throw error; }\n const entry: UploadedImage = { key, scope, buffer, surround: Float32Array.from(image.surround) };\n uploads.push(entry);\n while (uploads.length > KEPT_SCENES) uploads.shift()!.scope.release();\n return entry;\n };\n let checked: Promise<true | string> | null = null;\n const build = (gpu: DisplayViewGpuSetup, path: ChartCompositeProductPath): DisplayViewGpuMaterialModule => {\n const image = imagePlaneOf(gpu);\n if (!image || !gpu.placement) throw new ImageKernelExecutionError(\"unsupported-on-backend\", \"The setup carries no image-plane print and placement; use cpu-reference.\");\n const scene = image.scene, lattice = displayViewLatticeConstants(gpu.signalInput, gpu.placement, 0), rowBytes = scene.width * 12, banded = scene.height * rowBytes > runtime.maximumStorageBindingBytes;\n const params = new ArrayBuffer(4 * IMAGE_PLANE_PARAMS.words), words = new Uint32Array(params), floats = new Float32Array(params), P = IMAGE_PLANE_PARAMS;\n words[P.width] = scene.width; words[P.height] = scene.height; words[P.nearest] = scene.interpolation === \"nearest\" ? 1 : 0;\n const halfW = scene.width / 2, halfH = scene.height / (2 * scene.aspect);\n [floats[P.halfWHi], floats[P.halfWLo]] = dwSplit(halfW); [floats[P.halfHHi], floats[P.halfHLo]] = dwSplit(halfH); [floats[P.aspectHi], floats[P.aspectLo]] = dwSplit(scene.aspect);\n // The reference's float64 query point carries up to 10⁻¹⁴ frame units (the composite kernel's slack) times the pixels per frame unit.\n floats[P.slackX] = 1e-14 * gpu.placement.chartUnitsPerFrameUnit * halfW; floats[P.slackY] = 1e-14 * gpu.placement.chartUnitsPerFrameUnit * halfH;\n let code = wgsl.get(path);\n if (code === undefined) { code = imagePlaneMaterialWgsl(path); wgsl.set(path, code); }\n const base = { id: imagePlaneMaterialModuleId(path), wgsl: code, extraSiteRoundings: IMAGE_PLANE_EXTRA_SITE_ROUNDINGS, siteTable: Float32Array.from(image.surround) };\n if (!banded) {\n const uploaded = upload(image);\n return { ...base, bindings: [{ binding: 0, kind: \"storage\", buffer: uploaded.buffer }, { binding: 1, kind: \"uniform\", data: new Uint8Array(params) },\n { binding: 2, kind: \"uniform\", data: new Uint8Array(lattice.params) }, { binding: 3, kind: \"storage\", data: lattice.offsets }] };\n }\n // A photo larger than one binding: per band the pixel rows its native site rows reach. The print-local v of site row y and\n // query offset o is (y + c_o)·scale_v·k; the photo row is (aspect − v)·H/(2·aspect), plus two rows of margin either side.\n const offsetsV = Array.from({ length: lattice.offsets.length / 4 }, (_, o) => lattice.offsets[4 * o + 2]! + lattice.offsets[4 * o + 3]!);\n const rowOf = (y: number, c: number): number => (scene.aspect - (y + c) * lattice.scaleV * gpu.placement!.chartUnitsPerFrameUnit) * halfH;\n const rate = Math.abs(lattice.scaleV) * gpu.placement.chartUnitsPerFrameUnit * halfH, maximumRows = Math.floor(runtime.maximumStorageBindingBytes / rowBytes);\n return { ...base, bindings: [],\n bandRows: (sitesPerDisplayRow: number): number => Math.max(1, Math.floor(((maximumRows - 6) / rate - 6) / sitesPerDisplayRow)),\n band(scope, layout, y0, y1): GPUBindGroup {\n let low = Infinity, high = -Infinity;\n for (const y of [y0, y1]) for (const c of offsetsV) { const r = rowOf(y, c); low = Math.min(low, r); high = Math.max(high, r); }\n const j0 = Math.max(0, Math.min(scene.height - 1, Math.floor(low) - 2)), j1 = Math.max(j0, Math.min(scene.height - 1, Math.floor(high) + 2));\n if ((j1 - j0 + 1) * rowBytes > runtime.maximumStorageBindingBytes) throw new ImageKernelExecutionError(\"insufficient-limits\", \"A band's pixel signals exceed the device's storage binding limit.\");\n const bandParams = params.slice(0);\n new Uint32Array(bandParams)[P.row0] = j0;\n return runtime.device.createBindGroup({ layout, entries: [\n { binding: 0, resource: { buffer: bandBuffer(image, j0, j1 + 1) } },\n { binding: 1, resource: { buffer: scope.upload(\"photivra-display-view-image-params\", new Uint8Array(bandParams), BUFFER_USAGE.UNIFORM) } },\n { binding: 2, resource: { buffer: scope.upload(\"photivra-display-view-image-lattice\", new Uint8Array(lattice.params), BUFFER_USAGE.UNIFORM) } },\n { binding: 3, resource: { buffer: scope.upload(\"photivra-display-view-image-offsets\", lattice.offsets, BUFFER_USAGE.STORAGE) } }] });\n } };\n };\n // The module's self-check, once per runtime (single flight; a failure is retried on the next photo).\n const check = async (): Promise<void> => {\n checked ??= runImagePlaneConformance(runtime, undefined).catch((error: unknown) => { checked = null; throw error; });\n const verdict = await checked;\n if (verdict !== true) { checked = null; throw new ImageKernelExecutionError(\"unsupported-on-backend\", \"The image-plane module failed its self-check on this device: \" + verdict); }\n };\n return {\n async moduleFor(gpu, signal): Promise<DisplayViewGpuMaterialModule> { const path = (await probe(signal)).productPath ?? \"dekker\"; await check(); return build(gpu, path); },\n async qualityPasses(gpu, signal): Promise<DisplayViewQualityImagePasses> { const path = (await probe(signal)).productPath ?? \"dekker\"; await check(); return imagePlaneQualityPasses(runtime, gpu, path); },\n build,\n release(): void { for (const entry of uploads.splice(0)) entry.scope.release(); lastBand?.scope.release(); lastBand = null; }\n };\n}\n\n/**\n * #581's run-time self-check of the module, run on a device's first photo: a 12 × 8 photo (a color ramp with hard edges, every\n * lattice cell's corner colors among its pixels) printed at 0.8 of the frame's width on the 18 % surround of a 38 × 26 frame shown\n * at 13 × 9, the GPU against `renderDisplayView` within the a-priori bounds, every flagged pixel recomputed: the Speed kernel with\n * the 2 × 2 box, then the Quality passes with the four-spot filter's 16 offsets and synthetic radius-1 kernels at three nodes.\n * A device that fails the double-float32 probe refuses photos (unsupported-on-backend, as composite charts), so the check passes\n * there without keeping the device's charts off the GPU.\n */\nexport async function runImagePlaneConformance(handle: unknown, signal: AbortSignal | undefined): Promise<true | string> {\n const runtime = handle as WebGpuRuntime, support = imagePlaneSupport();\n if (!support) return true;\n const { nativeWidth, nativeHeight, frameWidth, nodes } = CONFORMANCE_FRAME, g = 2 / frameWidth;\n const width = 12, height = 8, data = new Uint8Array(width * height * 3);\n for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) for (let c = 0; c < 3; c++) data[(y * width + x) * 3 + c] = [(x * 23) % 256, (y * 37 + x * 5) % 256, x < 6 ? 255 - y * 30 : 10][c]!;\n const printWidth = 1.6, aspect = height / width, k = 2 / printWidth, surround = 0.18, placement = { chartUnitsPerFrameUnit: k, aspect };\n const scene = await support.resolveImagePlaneScene({ kind: \"image-plane\", sceneId: \"conformance\", image: { width, height, channels: 3, encoding: \"srgb-8\", data } }, aspect);\n const white = Float64Array.of(0.5, 0.9, 0.7), A = conformanceResponses(1);\n // The print's radiance as the provider forms it: the print-local point, the surround outside, times the white radiance at the node.\n const radianceAt = (u: number, v: number, nm: number): number => {\n const cu = u * k, cv = v * k;\n return (Math.abs(cu) <= 1 && Math.abs(cv) <= aspect ? scene.reflectanceAt(cu, cv, nm) : surround) * white[nodes.indexOf(nm)]!;\n };\n const printScene = scene.signalScene(nodes, A, white, radianceAt, k, 1, surround), readout = { perElectron: 1 / 60000, darkElectrons: 0.07, constantVariance: 1.5e-9 };\n const speedOffsets = [[-0.25, -0.25], [0.25, -0.25], [-0.25, 0.25], [0.25, 0.25]].map(([x, y]) => ({ x: x!, y: y!, weight: 0.25 }));\n const speedInput: DisplayViewExpectedSignalInput = { nativeWidth, nativeHeight, outputWidth: frameWidth, wavelengthsNm: nodes, electronsPerRadiance: A, offsets: speedOffsets, scene: printScene,\n channelAt: conformanceChannelAt, queryPoint: (x, y, o, out) => { out[0] = (x + 0.5 + speedOffsets[o]!.x - nativeWidth / 2) * g; out[1] = -(y + 0.5 + speedOffsets[o]!.y - nativeHeight / 2) * g; } };\n const speed = conformanceSetup(speedInput, readout, 581, 2, signal, { gpu: { signalInput: speedInput, chart: null, placement } });\n const qualityOffsets: { x: number; y: number; weight: number }[] = [];\n for (const [nx, ny] of [[-0.25, -0.25], [0.25, -0.25], [-0.25, 0.25], [0.25, 0.25]] as const) for (const [ax, ay] of [[-0.5, -0.5], [0.5, -0.5], [-0.5, 0.5], [0.5, 0.5]] as const) qualityOffsets.push({ x: nx - ax, y: ny - ay, weight: 1 / 16 });\n const kernel = (sigma: number): Float64Array => { const w = Float64Array.from({ length: 9 }, (_, t) => Math.exp(-0.5 * (((t % 3) - 1) ** 2 + (Math.floor(t / 3) - 1) ** 2) / (sigma * sigma))); const sum = w.reduce((a, b) => a + b, 0); return w.map((v) => v / sum); };\n const qualityInput: DisplayViewExpectedSignalInput = { nativeWidth, nativeHeight, outputWidth: frameWidth, wavelengthsNm: nodes, electronsPerRadiance: A, offsets: qualityOffsets,\n kernels: { radius: 1, perNode: [kernel(0.6), kernel(0.7), kernel(0.8)] }, scene: printScene, channelAt: conformanceChannelAt };\n const quality = conformanceSetup(qualityInput, readout, 582, 5, signal, { gpu: { signalInput: qualityInput, chart: null, placement } });\n const [speedReference, qualityReference] = [await renderDisplayView(speed), await renderDisplayView(quality)];\n const images = createDisplayViewImageModules(runtime, (s) => probeChartCompositeDevice(runtime, (label, code) => createComputePipeline(runtime, label, code, s), s));\n try {\n return await withConformanceAbort(runtime, signal, async (abort, pipelines) => {\n let path: \"dekker\" | \"fma\";\n try { path = (await probeChartCompositeDevice(runtime, pipelines, abort.signal)).productPath ?? \"dekker\"; } catch (error) {\n if (error instanceof ChartCompositeProbeError) return true;\n throw error;\n }\n const verdict = conformanceVerdict(speedReference, await renderDisplayViewSpeedOnGpu(runtime, 1 << 20, { setup: speed, signalInput: speedInput, material: images.build(speed.gpu!, path) }, abort, undefined, pipelines));\n if (verdict !== true) return \"Speed: \" + verdict;\n const gpu = await renderDisplayViewQualityOnGpu(runtime, 1 << 20, { setup: quality, signalInput: qualityInput, material: { id: \"image-plane\", wgsl: \"\", bindings: [] },\n image: imagePlaneQualityPasses(runtime, quality.gpu!, path) }, abort, undefined, pipelines);\n const qualityVerdict = conformanceVerdict(qualityReference, gpu);\n return qualityVerdict === true ? true : \"Quality: \" + qualityVerdict;\n });\n } finally { images.release(); }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"display-view-image-material-module.js","sourceRoot":"","sources":["../../src/gpu/display-view-image-material-module.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The image-plane module of the GPU display view (#581): the Speed kernel's `scene_value` (the seam of #478 and #491,\n * `DisplayViewGpuMaterialModule`) for an image-plane print, so that a photo renders on the device like a chart.\n *\n * **What the reference computes** at a query point (expected-signal.ts, the direct path's `signalAt`): the print-local point\n * cu = u·m/h, cv = v·m/h (outside |cu| ≤ 1, |cv| ≤ aspect the surround: its reflectance times the neutral signal N_c); the\n * pixel coordinates X = (cu + 1)·W/2, Y = (aspect − cv)·H/(2·aspect); then the bilinear weights of the four nearest pixel\n * centers (clamped to the edge) times each pixel's channel signal S_j,c = Σ_n A_c(λ_n)·ρ_j(λ_n)·W_n, integrated from the pixel's\n * reconstructed spectrum ρ_j (its cell's eight node spectra blended, then the paper; `ResolvedImagePlaneScene.pixelSignals`), or\n * the nearest pixel's. No per-channel values of the lattice nodes are formed.\n *\n * **On the device.** The host computes every pixel's S_j,c in float64 and rounds it once to float32 (3 values per pixel). When\n * they fit one storage binding they are uploaded once per scene and kept on the device while the renderer lives; otherwise each\n * band of a render builds and uploads only its rows. Either way they are built and written 4 MiB of rows at a time, so the host\n * never holds more than that of S (owner decision 2026-11-09; the bytes are those of the whole array). The module recovers the exact lattice point from the\n * kernel's float32 point as the composite module does (`LATTICE_POINT_WGSL`, about 2⁻⁴⁶ relative), forms cu, cv, X and Y\n * in double-float32 and decides the print's edge in the composite kernel's bound arithmetic (a point within its bound of the\n * edge is flagged: the display pixel is recomputed on the host). Per axis it splits s = X − ½ into its integer part n and\n * fraction f exactly (double-float32), rounds the smaller of f and 1 − f once to float32 and forms the other as 1 minus it, so\n * each weight carries at most 2E relative error (E = 2⁻²³) besides the point's own error. The point's error moves weight\n * between neighbors: with δ the bound of |X_gpu − X_ref| in pixels (4·(2⁻⁴⁰·(|X| + 1)) + 4·10⁻¹⁴·W/2·k: the recovery, the\n * double-float32 steps and the reference's own float64 rounding of its query point, generously), the value moves by at most\n * (δx + δy)·2·max S, and the point is flagged when that exceeds E times the value. So an unflagged value carries a relative\n * error only: S's rounding 1, the weights 2 + 2, the two products and two sums 4, the flag's budget 1, that is 10 roundings\n * beyond the table lookup's one (`extraSiteRoundings`), added to the Speed kernel's chains (docs/WEBGPU.md, \"Display view (Speed)\").\n * `nearest` takes the pixel under the point, flagging a point within its bound of a pixel edge (`bfloor`). All S are\n * non-negative (non-negative responses, illuminant and spectra), so the weighted sums need no cancellation term.\n *\n * The surround's three channel signals, integrated from its spectrum (its reflectance times the white radiance at each node) like\n * a pixel's, are the kernel's binding 3 (`spectral_table`, which this module does not otherwise use).\n */\n\nimport { ImageKernelExecutionError, type ChartCompositeProbeRecord } from \"./image-kernel-execution.js\";\nimport { BUFFER_USAGE, GpuResourceScope, type WebGpuRuntime } from \"./webgpu-runtime.js\";\nimport { dwSplit } from \"./chart-composite-gpu.js\";\nimport type { ChartCompositeProductPath } from \"./wgsl-chart-composite-kernel.js\";\nimport { displayViewModuleCommonWgsl, displayViewLatticeConstants, LATTICE_BINDINGS_WGSL, LATTICE_POINT_WGSL } from \"./display-view-composite-material-module.js\";\nimport type { DisplayViewGpuMaterialModule } from \"./display-view-speed-gpu.js\";\nimport { renderDisplayView, type DisplayViewGpuSetup } from \"../facade/display-view.js\";\nimport type { DisplayViewExpectedSignalInput } from \"../facade/expected-signal.js\";\nimport { resolveCaptureIlluminant, type ImagePlaneSignalScene } from \"../facade/scene-radiance.js\";\nimport { resolveMixedIllumination } from \"../facade/mixed-illumination.js\";\nimport { imagePlaneSupport } from \"../facade/image-plane-support.js\";\nimport { CONFORMANCE_FRAME, conformanceChannelAt, conformanceResponses, conformanceSetup, conformanceVerdict, renderDisplayViewSpeedOnGpu, withConformanceAbort } from \"./display-view-speed-gpu.js\";\nimport { renderDisplayViewQualityOnGpu, type DisplayViewQualityImagePasses } from \"./display-view-quality-gpu.js\";\nimport { imagePlaneQualityPasses } from \"./display-view-image-quality.js\";\nimport { ChartCompositeProbeError, probeChartCompositeDevice } from \"./chart-composite-gpu.js\";\nimport { createComputePipeline } from \"./webgpu-runtime.js\";\n\n/** The module's id per product path. */\nexport function imagePlaneMaterialModuleId(path: ChartCompositeProductPath): string { return path === \"dekker\" ? \"image-plane\" : \"image-plane-fma\"; }\n/** Roundings of the module's value beyond the table lookup's one (see the module comment). */\nexport const IMAGE_PLANE_EXTRA_SITE_ROUNDINGS = 10;\n/** Layout of the photo uniform (float32 / u32 words, 64 bytes). */\nexport const IMAGE_PLANE_PARAMS = /* @__PURE__ */ Object.freeze({ width: 0, height: 1, nearest: 2, row0: 3, halfWHi: 4, halfWLo: 5, halfHHi: 6, halfHLo: 7, aspectHi: 8, aspectLo: 9,\n slackX: 10, slackY: 11, words: 16 });\n/** Table values above this are outside the float32 domain. */\nconst FLOAT32_SAFE_MAGNITUDE = 2 ** 120;\n/** Host bytes of pixel signals built per write (whole uploads and bands). */\nconst UPLOAD_CHUNK_BYTES = 4 << 20;\n/** Scenes whose pixel signals stay uploaded per renderer. */\nconst KEPT_SCENES = 2;\n\n/** The module's WGSL with one product path (see the module comment). */\nexport function imagePlaneMaterialWgsl(path: ChartCompositeProductPath = \"dekker\"): string {\n return `${displayViewModuleCommonWgsl(path)}\n@group(1) @binding(0) var<storage, read> photo_signal: array<f32>;\nstruct PhotoParams {\n width: u32, height: u32, nearest: u32, row0: u32,\n half_w_hi: f32, half_w_lo: f32, half_h_hi: f32, half_h_lo: f32,\n aspect_hi: f32, aspect_lo: f32, slack_x: f32, slack_y: f32,\n pad1: f32, pad2: f32, pad3: f32, pad4: f32,\n};\n@group(1) @binding(1) var<uniform> photo: PhotoParams;\n${LATTICE_BINDINGS_WGSL}\n${LATTICE_POINT_WGSL}\n// The point's error bound in pixels along one axis (see the module comment).\nfn pixel_slack(x: D, slack: f32) -> f32 { return 4.0 * (DW * (abs(x.h) + 1.0)) + 4.0 * slack; }\n// One axis of the bilinear weights: the pixel pair (clamped to the edge) and the weights of s = X − 1/2.\nstruct Axis { i0: u32, i1: u32, w0: f32, w1: f32 }\nfn bilinear_axis(s: D, n: u32) -> Axis {\n var f0 = floor(s.h);\n if (f0 == s.h && s.l < 0.0) { f0 = f0 - 1.0; }\n let frac = d_sub(s, D(f0, 0.0));\n let comp = d_sub(D(ob(f0 + 1.0), 0.0), s);\n var w0 = 0.0; var w1 = 0.0;\n if (frac.h <= 0.5) { w1 = ob(frac.h + frac.l); w0 = ob(1.0 - w1); } else { w0 = ob(comp.h + comp.l); w1 = ob(1.0 - w0); }\n let last = i32(n) - 1;\n return Axis(u32(clamp(i32(f0), 0, last)), u32(clamp(i32(f0) + 1, 0, last)), w0, w1);\n}\nfn photo_at(i: u32, j: u32, c: u32) -> f32 { return photo_signal[((j - photo.row0) * photo.width + i) * 3u + c]; }\nfn scene_value(p: vec2<f32>, c: u32) -> f32 {\n let k = D(lattice.chart_k_hi, lattice.chart_k_lo);\n let u = d_mul(lattice_point(p.x, D(lattice.scale_u_hi, lattice.scale_u_lo), 0u), k);\n let v = d_mul(lattice_point(p.y, D(lattice.scale_v_hi, lattice.scale_v_lo), 1u), k);\n let aspect = D(photo.aspect_hi, photo.aspect_lo);\n if (!(le(babs(bd(u)), bx(1.0)) && le(babs(bd(v)), bd(aspect)))) { return spectral_table[c]; }\n let x = d_mul(d_add(u, D(1.0, 0.0)), D(photo.half_w_hi, photo.half_w_lo));\n let y = d_mul(d_sub(aspect, v), D(photo.half_h_hi, photo.half_h_lo));\n if (photo.nearest != 0u) {\n let last_x = f32(photo.width - 1u);\n let last_y = f32(photo.height - 1u);\n let i = u32(clamp(bfloor(bd(x), 1.0, last_x), 0.0, last_x));\n let j = u32(clamp(bfloor(bd(y), 1.0, last_y), 0.0, last_y));\n return photo_at(i, j, c);\n }\n let ax = bilinear_axis(d_sub(x, D(0.5, 0.0)), photo.width);\n let ay = bilinear_axis(d_sub(y, D(0.5, 0.0)), photo.height);\n let s00 = photo_at(ax.i0, ay.i0, c);\n let s10 = photo_at(ax.i1, ay.i0, c);\n let s01 = photo_at(ax.i0, ay.i1, c);\n let s11 = photo_at(ax.i1, ay.i1, c);\n let value = ob(ob(ay.w0 * ob(ob(ax.w0 * s00) + ob(ax.w1 * s10))) + ob(ay.w1 * ob(ob(ax.w0 * s01) + ob(ax.w1 * s11))));\n let largest = max(max(s00, s10), max(s01, s11));\n let moved = (pixel_slack(x, photo.slack_x) + pixel_slack(y, photo.slack_y)) * 2.0 * largest;\n if (!(moved <= E * value)) { material_uncertain = true; }\n return value;\n}\n`;\n}\n\n/** The image-plane print behind a GPU setup's expected signal (`ImagePlaneSignalScene.image`), or undefined. */\nexport function imagePlaneOf(gpu: DisplayViewGpuSetup): ImagePlaneSignalScene[\"image\"] | undefined {\n return (gpu.signalInput.scene as { image?: ImagePlaneSignalScene[\"image\"] }).image;\n}\n/** The pixel signals of a scene on the device (per renderer), keyed by the signal scene's image record. */\ninterface UploadedImage { key: object; scope: GpuResourceScope; buffer: GPUBuffer; surround: Float32Array<ArrayBuffer> }\n\n/** The image-plane modules of one display-view renderer: `moduleFor` builds the setup's module (its uploads kept), `release` frees them. */\nexport interface DisplayViewImageModules {\n /** The setup's module; the first call on a runtime runs the module's self-check (`runImagePlaneConformance`) and refuses the device if it fails. */\n moduleFor(gpu: DisplayViewGpuSetup, signal: AbortSignal): Promise<DisplayViewGpuMaterialModule>;\n /** The setup's module without the self-check (the self-check itself uses it). */\n build(gpu: DisplayViewGpuSetup, path: ChartCompositeProductPath): DisplayViewGpuMaterialModule;\n /** #581: the print's Quality passes 1 and 2 (src/gpu/display-view-image-quality.ts), after the same self-check. */\n qualityPasses(gpu: DisplayViewGpuSetup, signal: AbortSignal): Promise<DisplayViewQualityImagePasses>;\n release(): void;\n}\n\n/**\n * The image-plane modules of a renderer; `probe` is the composite module's device probe (single flight), whose double-word product\n * path the module's double-float32 takes.\n */\nexport function createDisplayViewImageModules(runtime: WebGpuRuntime, probe: (signal: AbortSignal) => Promise<ChartCompositeProbeRecord>): DisplayViewImageModules {\n const uploads: UploadedImage[] = [], wgsl = new Map<ChartCompositeProductPath, string>();\n // Pixel rows [j0, j1)'s channel signals, built on demand so that the host holds one chunk or band (#581): each pixel's signals\n // integrated from its reconstructed spectrum (`pixelSignals`, the reference's own float64 values), rounded once.\n const pixel = new Float64Array(3);\n const rowsOf = (image: ImagePlaneSignalScene[\"image\"], j0: number, j1: number): Float32Array<ArrayBuffer> => {\n const { scene, nodes } = image, values = new Float32Array((j1 - j0) * scene.width * 3);\n for (let j = j0 * scene.width, o = 0; j < j1 * scene.width; j++) {\n scene.pixelSignals(j, nodes, pixel, 0);\n for (let c = 0; c < 3; c++) {\n const value = pixel[c]!;\n if (!(value >= 0 && value <= FLOAT32_SAFE_MAGNITUDE)) throw new ImageKernelExecutionError(\"unsupported-float32-domain\", \"A pixel's channel signal is outside the float32 domain.\");\n values[o++] = value;\n }\n }\n return values;\n };\n // Rows [a, b)'s signals written to `buffer` (whose first row is `base`), built UPLOAD_CHUNK_BYTES of rows at a time.\n const fill = (buffer: GPUBuffer, image: ImagePlaneSignalScene[\"image\"], a: number, b: number, base: number): void => {\n const rowBytes = image.scene.width * 12, chunk = Math.max(1, Math.floor(UPLOAD_CHUNK_BYTES / rowBytes));\n for (let j = a; j < b; j += chunk) { const rows = rowsOf(image, j, Math.min(b, j + chunk)); runtime.device.queue.writeBuffer(buffer, (j - base) * rowBytes, rows.buffer, 0, rows.byteLength); }\n };\n const rowsBuffer = (scope: GpuResourceScope, label: string, image: ImagePlaneSignalScene[\"image\"], j0: number, j1: number): GPUBuffer => {\n const buffer = scope.buffer(label, (j1 - j0) * image.scene.width * 12, BUFFER_USAGE.STORAGE | BUFFER_USAGE.COPY_DST);\n fill(buffer, image, j0, j1, j0);\n return buffer;\n };\n // The latest band's rows stay on the device until the next band: the rows the two share are copied there on the device, and\n // only the others are built on the host (the same bytes; the host still holds one chunk at most).\n let lastBand: { image: object; j0: number; j1: number; scope: GpuResourceScope; buffer: GPUBuffer } | null = null;\n const bandBuffer = (image: ImagePlaneSignalScene[\"image\"], j0: number, j1: number): GPUBuffer => {\n const rowBytes = image.scene.width * 12, scope = new GpuResourceScope(runtime), last = lastBand?.image === image ? lastBand : null;\n try {\n const buffer = scope.buffer(\"photivra-display-view-image-signal-band\", (j1 - j0) * rowBytes, BUFFER_USAGE.STORAGE | BUFFER_USAGE.COPY_DST | BUFFER_USAGE.COPY_SRC);\n const o0 = last ? Math.max(j0, last.j0) : j0, o1 = last ? Math.min(j1, last.j1) : j0;\n if (o1 > o0) {\n const encoder = runtime.device.createCommandEncoder({ label: \"photivra-display-view-image-band-rows\" });\n encoder.copyBufferToBuffer(last!.buffer, (o0 - last!.j0) * rowBytes, buffer, (o0 - j0) * rowBytes, (o1 - o0) * rowBytes);\n runtime.device.queue.submit([encoder.finish()]);\n fill(buffer, image, j0, o0, j0); fill(buffer, image, o1, j1, j0);\n } else fill(buffer, image, j0, j1, j0);\n lastBand?.scope.release();\n lastBand = { image, j0, j1, scope, buffer };\n return buffer;\n } catch (error) { scope.release(); throw error; }\n };\n const upload = (image: ImagePlaneSignalScene[\"image\"]): UploadedImage => {\n const key = image as object, index = uploads.findIndex((e) => e.key === key);\n if (index >= 0) { const [entry] = uploads.splice(index, 1); uploads.push(entry!); return entry!; }\n const scope = new GpuResourceScope(runtime);\n let buffer: GPUBuffer;\n try { buffer = rowsBuffer(scope, \"photivra-display-view-image-signal\", image, 0, image.scene.height); } catch (error) { scope.release(); throw error; }\n const entry: UploadedImage = { key, scope, buffer, surround: Float32Array.from(image.surround) };\n uploads.push(entry);\n while (uploads.length > KEPT_SCENES) uploads.shift()!.scope.release();\n return entry;\n };\n let checked: Promise<true | string> | null = null;\n const build = (gpu: DisplayViewGpuSetup, path: ChartCompositeProductPath): DisplayViewGpuMaterialModule => {\n const image = imagePlaneOf(gpu);\n if (!image || !gpu.placement) throw new ImageKernelExecutionError(\"unsupported-on-backend\", \"The setup carries no image-plane print and placement; use cpu-reference.\");\n const scene = image.scene, lattice = displayViewLatticeConstants(gpu.signalInput, gpu.placement, 0), rowBytes = scene.width * 12, banded = scene.height * rowBytes > runtime.maximumStorageBindingBytes;\n const params = new ArrayBuffer(4 * IMAGE_PLANE_PARAMS.words), words = new Uint32Array(params), floats = new Float32Array(params), P = IMAGE_PLANE_PARAMS;\n words[P.width] = scene.width; words[P.height] = scene.height; words[P.nearest] = scene.interpolation === \"nearest\" ? 1 : 0;\n const halfW = scene.width / 2, halfH = scene.height / (2 * scene.aspect);\n [floats[P.halfWHi], floats[P.halfWLo]] = dwSplit(halfW); [floats[P.halfHHi], floats[P.halfHLo]] = dwSplit(halfH); [floats[P.aspectHi], floats[P.aspectLo]] = dwSplit(scene.aspect);\n // The reference's float64 query point carries up to 10⁻¹⁴ frame units (the composite kernel's slack) times the pixels per frame unit.\n floats[P.slackX] = 1e-14 * gpu.placement.chartUnitsPerFrameUnit * halfW; floats[P.slackY] = 1e-14 * gpu.placement.chartUnitsPerFrameUnit * halfH;\n let code = wgsl.get(path);\n if (code === undefined) { code = imagePlaneMaterialWgsl(path); wgsl.set(path, code); }\n const base = { id: imagePlaneMaterialModuleId(path), wgsl: code, extraSiteRoundings: IMAGE_PLANE_EXTRA_SITE_ROUNDINGS, siteTable: Float32Array.from(image.surround) };\n if (!banded) {\n const uploaded = upload(image);\n return { ...base, bindings: [{ binding: 0, kind: \"storage\", buffer: uploaded.buffer }, { binding: 1, kind: \"uniform\", data: new Uint8Array(params) },\n { binding: 2, kind: \"uniform\", data: new Uint8Array(lattice.params) }, { binding: 3, kind: \"storage\", data: lattice.offsets }] };\n }\n // A photo larger than one binding: per band the pixel rows its native site rows reach. The print-local v of site row y and\n // query offset o is (y + c_o)·scale_v·k; the photo row is (aspect − v)·H/(2·aspect), plus two rows of margin either side.\n const offsetsV = Array.from({ length: lattice.offsets.length / 4 }, (_, o) => lattice.offsets[4 * o + 2]! + lattice.offsets[4 * o + 3]!);\n const rowOf = (y: number, c: number): number => (scene.aspect - (y + c) * lattice.scaleV * gpu.placement!.chartUnitsPerFrameUnit) * halfH;\n const rate = Math.abs(lattice.scaleV) * gpu.placement.chartUnitsPerFrameUnit * halfH, maximumRows = Math.floor(runtime.maximumStorageBindingBytes / rowBytes);\n return { ...base, bindings: [],\n bandRows: (sitesPerDisplayRow: number): number => Math.max(1, Math.floor(((maximumRows - 6) / rate - 6) / sitesPerDisplayRow)),\n band(scope, layout, y0, y1): GPUBindGroup {\n let low = Infinity, high = -Infinity;\n for (const y of [y0, y1]) for (const c of offsetsV) { const r = rowOf(y, c); low = Math.min(low, r); high = Math.max(high, r); }\n const j0 = Math.max(0, Math.min(scene.height - 1, Math.floor(low) - 2)), j1 = Math.max(j0, Math.min(scene.height - 1, Math.floor(high) + 2));\n if ((j1 - j0 + 1) * rowBytes > runtime.maximumStorageBindingBytes) throw new ImageKernelExecutionError(\"insufficient-limits\", \"A band's pixel signals exceed the device's storage binding limit.\");\n const bandParams = params.slice(0);\n new Uint32Array(bandParams)[P.row0] = j0;\n return runtime.device.createBindGroup({ layout, entries: [\n { binding: 0, resource: { buffer: bandBuffer(image, j0, j1 + 1) } },\n { binding: 1, resource: { buffer: scope.upload(\"photivra-display-view-image-params\", new Uint8Array(bandParams), BUFFER_USAGE.UNIFORM) } },\n { binding: 2, resource: { buffer: scope.upload(\"photivra-display-view-image-lattice\", new Uint8Array(lattice.params), BUFFER_USAGE.UNIFORM) } },\n { binding: 3, resource: { buffer: scope.upload(\"photivra-display-view-image-offsets\", lattice.offsets, BUFFER_USAGE.STORAGE) } }] });\n } };\n };\n // The module's self-check, once per runtime (single flight; a failure is retried on the next photo).\n const check = async (): Promise<void> => {\n checked ??= runImagePlaneConformance(runtime, undefined).catch((error: unknown) => { checked = null; throw error; });\n const verdict = await checked;\n if (verdict !== true) { checked = null; throw new ImageKernelExecutionError(\"unsupported-on-backend\", \"The image-plane module failed its self-check on this device: \" + verdict); }\n };\n return {\n async moduleFor(gpu, signal): Promise<DisplayViewGpuMaterialModule> { const path = (await probe(signal)).productPath ?? \"dekker\"; await check(); return build(gpu, path); },\n async qualityPasses(gpu, signal): Promise<DisplayViewQualityImagePasses> { const path = (await probe(signal)).productPath ?? \"dekker\"; await check(); return imagePlaneQualityPasses(runtime, gpu, path); },\n build,\n release(): void { for (const entry of uploads.splice(0)) entry.scope.release(); lastBand?.scope.release(); lastBand = null; }\n };\n}\n\n/**\n * #581's run-time self-check of the module, run on a device's first photo: a 12 × 8 photo (a color ramp with hard edges, every\n * lattice cell's corner colors among its pixels) printed at 0.8 of the frame's width on the 18 % surround of a 38 × 26 frame shown\n * at 13 × 9, the GPU against `renderDisplayView` within the a-priori bounds, every flagged pixel recomputed: the Speed kernel with\n * the 2 × 2 box, then the Quality passes with the four-spot filter's 16 offsets and synthetic radius-1 kernels at three nodes, and\n * (#597) the same passes under mixed light (a three-source gradient with a hard edge and a point source).\n * A device that fails the double-float32 probe refuses photos (unsupported-on-backend, as composite charts), so the check passes\n * there without keeping the device's charts off the GPU.\n */\nexport async function runImagePlaneConformance(handle: unknown, signal: AbortSignal | undefined): Promise<true | string> {\n const runtime = handle as WebGpuRuntime, support = imagePlaneSupport();\n if (!support) return true;\n const { nativeWidth, nativeHeight, frameWidth, nodes } = CONFORMANCE_FRAME, g = 2 / frameWidth;\n const width = 12, height = 8, data = new Uint8Array(width * height * 3);\n for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) for (let c = 0; c < 3; c++) data[(y * width + x) * 3 + c] = [(x * 23) % 256, (y * 37 + x * 5) % 256, x < 6 ? 255 - y * 30 : 10][c]!;\n const printWidth = 1.6, aspect = height / width, k = 2 / printWidth, surround = 0.18, placement = { chartUnitsPerFrameUnit: k, aspect };\n const scene = await support.resolveImagePlaneScene({ kind: \"image-plane\", sceneId: \"conformance\", image: { width, height, channels: 3, encoding: \"srgb-8\", data } }, aspect);\n const white = Float64Array.of(0.5, 0.9, 0.7), A = conformanceResponses(1);\n // The print's radiance as the provider forms it: the print-local point, the surround outside, times the white radiance at the node.\n const radianceAt = (u: number, v: number, nm: number): number => {\n const cu = u * k, cv = v * k;\n return (Math.abs(cu) <= 1 && Math.abs(cv) <= aspect ? scene.reflectanceAt(cu, cv, nm) : surround) * white[nodes.indexOf(nm)]!;\n };\n const printScene = scene.signalScene(nodes, A, white, radianceAt, k, 1, surround), readout = { perElectron: 1 / 60000, darkElectrons: 0.07, constantVariance: 1.5e-9 };\n const speedOffsets = [[-0.25, -0.25], [0.25, -0.25], [-0.25, 0.25], [0.25, 0.25]].map(([x, y]) => ({ x: x!, y: y!, weight: 0.25 }));\n const speedInput: DisplayViewExpectedSignalInput = { nativeWidth, nativeHeight, outputWidth: frameWidth, wavelengthsNm: nodes, electronsPerRadiance: A, offsets: speedOffsets, scene: printScene,\n channelAt: conformanceChannelAt, queryPoint: (x, y, o, out) => { out[0] = (x + 0.5 + speedOffsets[o]!.x - nativeWidth / 2) * g; out[1] = -(y + 0.5 + speedOffsets[o]!.y - nativeHeight / 2) * g; } };\n const speed = conformanceSetup(speedInput, readout, 581, 2, signal, { gpu: { signalInput: speedInput, chart: null, placement } });\n const qualityOffsets: { x: number; y: number; weight: number }[] = [];\n for (const [nx, ny] of [[-0.25, -0.25], [0.25, -0.25], [-0.25, 0.25], [0.25, 0.25]] as const) for (const [ax, ay] of [[-0.5, -0.5], [0.5, -0.5], [-0.5, 0.5], [0.5, 0.5]] as const) qualityOffsets.push({ x: nx - ax, y: ny - ay, weight: 1 / 16 });\n const kernel = (sigma: number): Float64Array => { const w = Float64Array.from({ length: 9 }, (_, t) => Math.exp(-0.5 * (((t % 3) - 1) ** 2 + (Math.floor(t / 3) - 1) ** 2) / (sigma * sigma))); const sum = w.reduce((a, b) => a + b, 0); return w.map((v) => v / sum); };\n const qualityInput: DisplayViewExpectedSignalInput = { nativeWidth, nativeHeight, outputWidth: frameWidth, wavelengthsNm: nodes, electronsPerRadiance: A, offsets: qualityOffsets,\n kernels: { radius: 1, perNode: [kernel(0.6), kernel(0.7), kernel(0.8)] }, scene: printScene, channelAt: conformanceChannelAt };\n const quality = conformanceSetup(qualityInput, readout, 582, 5, signal, { gpu: { signalInput: qualityInput, chart: null, placement } });\n // #597: the same Quality case under mixed light: a gradient of three sources with a hard edge (equal stops) across the print, and a\n // point source over its upper left, the reference's irradiance from the same parts in float64.\n const day = { kind: \"planckian\" as const, temperatureKelvin: 6500 }, lamp = { kind: \"cie-a\" as const };\n const light = resolveMixedIllumination({ sources: [{ illuminant: day, illuminanceLux: 1.2e5 }, { illuminant: lamp, illuminanceLux: 8e4 }, { illuminant: day, illuminanceLux: 3e4 }],\n blend: { kind: \"linear-gradient\", from: { u: -0.9, v: 0.1 }, to: { u: 0.8, v: -0.2 }, stops: [0, 0.45, 0.45] },\n points: [{ illuminant: lamp, position: { xM: -0.3, yM: 0.2, heightM: 0.35 }, intensity: { illuminanceLux: 6e4, distanceM: 0.35 } }] }, resolveCaptureIlluminant);\n // The print's half width is 1 m here (print-local units are metres), so the point sources read the print-local point.\n const litIrradiance = (cu: number, cv: number, nm: number): number => light.irradianceAt(cu, cv, cu, cv, nm);\n const litRadianceAt = (u: number, v: number, nm: number): number => {\n const cu = u * k, cv = v * k;\n return (Math.abs(cu) <= 1 && Math.abs(cv) <= aspect ? scene.reflectanceAt(cu, cv, nm) : surround) * litIrradiance(cu, cv, nm) / Math.PI;\n };\n const litInput: DisplayViewExpectedSignalInput = { ...qualityInput, scene: scene.signalScene(nodes, A, white, litRadianceAt, k, 1, surround, light) };\n const lit = conformanceSetup(litInput, readout, 597, 5, signal, { gpu: { signalInput: litInput, chart: null, placement } });\n const [speedReference, qualityReference, litReference] = [await renderDisplayView(speed), await renderDisplayView(quality), await renderDisplayView(lit)];\n const images = createDisplayViewImageModules(runtime, (s) => probeChartCompositeDevice(runtime, (label, code) => createComputePipeline(runtime, label, code, s), s));\n try {\n return await withConformanceAbort(runtime, signal, async (abort, pipelines) => {\n let path: \"dekker\" | \"fma\";\n try { path = (await probeChartCompositeDevice(runtime, pipelines, abort.signal)).productPath ?? \"dekker\"; } catch (error) {\n if (error instanceof ChartCompositeProbeError) return true;\n throw error;\n }\n const verdict = conformanceVerdict(speedReference, await renderDisplayViewSpeedOnGpu(runtime, 1 << 20, { setup: speed, signalInput: speedInput, material: images.build(speed.gpu!, path) }, abort, undefined, pipelines));\n if (verdict !== true) return \"Speed: \" + verdict;\n const gpu = await renderDisplayViewQualityOnGpu(runtime, 1 << 20, { setup: quality, signalInput: qualityInput, material: { id: \"image-plane\", wgsl: \"\", bindings: [] },\n image: imagePlaneQualityPasses(runtime, quality.gpu!, path) }, abort, undefined, pipelines);\n const qualityVerdict = conformanceVerdict(qualityReference, gpu);\n if (qualityVerdict !== true) return \"Quality: \" + qualityVerdict;\n const litGpu = await renderDisplayViewQualityOnGpu(runtime, 1 << 20, { setup: lit, signalInput: litInput, material: { id: \"image-plane\", wgsl: \"\", bindings: [] },\n image: imagePlaneQualityPasses(runtime, lit.gpu!, path) }, abort, undefined, pipelines);\n const litVerdict = conformanceVerdict(litReference, litGpu);\n return litVerdict === true ? true : \"Quality under mixed light: \" + litVerdict;\n });\n } finally { images.release(); }\n}\n"]}
|
|
@@ -3,8 +3,39 @@ import type { ChartCompositeProductPath } from "./wgsl-chart-composite-kernel.js
|
|
|
3
3
|
import { type DisplayViewQualityImagePasses, type SignalGather } from "./display-view-quality-gpu.js";
|
|
4
4
|
import { type DisplayViewExpectedSignalInput } from "../facade/expected-signal.js";
|
|
5
5
|
import type { DisplayViewGpuSetup } from "../facade/display-view.js";
|
|
6
|
+
import { type ImagePlaneSignalScene } from "../facade/scene-radiance.js";
|
|
6
7
|
/** Relative roundings of a lattice point's radiance (see the module comment). */
|
|
7
8
|
export declare const IMAGE_PLANE_LATTICE_U = 32;
|
|
9
|
+
/**
|
|
10
|
+
* #597: relative roundings of the mixed light at a lattice point (a point whose computed bound exceeds IMAGE_PLANE_LIGHT_U − 1 is
|
|
11
|
+
* flagged; see the module comment), added to IMAGE_PLANE_LATTICE_U for a lit print.
|
|
12
|
+
*/
|
|
13
|
+
export declare const IMAGE_PLANE_LIGHT_U = 40;
|
|
14
|
+
/** #597: layout of the light table (float32 / u32 words; see `imagePlaneLightTable`). */
|
|
15
|
+
export declare const IMAGE_PLANE_LIGHT: Readonly<{
|
|
16
|
+
kind: 0;
|
|
17
|
+
sources: 1;
|
|
18
|
+
points: 2;
|
|
19
|
+
regions: 3;
|
|
20
|
+
outside: 4;
|
|
21
|
+
regionsAt: 6;
|
|
22
|
+
pointsAt: 7;
|
|
23
|
+
tablesAt: 8;
|
|
24
|
+
slack: 9;
|
|
25
|
+
surround: 10;
|
|
26
|
+
maximumInverse: 11;
|
|
27
|
+
halfHi: 12;
|
|
28
|
+
halfLo: 13;
|
|
29
|
+
aU: 16;
|
|
30
|
+
aV: 18;
|
|
31
|
+
dU: 20;
|
|
32
|
+
dV: 22;
|
|
33
|
+
inverse: 24;
|
|
34
|
+
stops: 26;
|
|
35
|
+
regionWords: 9;
|
|
36
|
+
pointWords: 6;
|
|
37
|
+
maximumPoints: 8;
|
|
38
|
+
}>;
|
|
8
39
|
/** Layout of the photo uniform (u32 / float32 words, 96 bytes). */
|
|
9
40
|
export declare const IMAGE_PLANE_QUALITY_PARAMS: Readonly<{
|
|
10
41
|
width: 0;
|
|
@@ -13,6 +44,7 @@ export declare const IMAGE_PLANE_QUALITY_PARAMS: Readonly<{
|
|
|
13
44
|
nodes: 3;
|
|
14
45
|
row0: 4;
|
|
15
46
|
zero: 5;
|
|
47
|
+
lit: 6;
|
|
16
48
|
suHi: 8;
|
|
17
49
|
suLo: 9;
|
|
18
50
|
svHi: 10;
|
|
@@ -31,6 +63,16 @@ export declare const IMAGE_PLANE_QUALITY_PARAMS: Readonly<{
|
|
|
31
63
|
span: 23;
|
|
32
64
|
words: 24;
|
|
33
65
|
}>;
|
|
66
|
+
/**
|
|
67
|
+
* #597: the light table of a lit print at the spectral nodes (the layout `IMAGE_PLANE_LIGHT`): the blend (kind, sources, its geometry
|
|
68
|
+
* and stops with each segment's inverse width, 0 at a hard edge), the regions, the point sources (x, y, h in metres), then per node
|
|
69
|
+
* T_i,n = k_i·S_i(λ_n)/π for each blend source and c_j·S_j(λ_n)/π for each point source: spectra only, no channel value. `slack` is the
|
|
70
|
+
* reference's own rounding of a query point in print-local units.
|
|
71
|
+
*/
|
|
72
|
+
export declare function imagePlaneLightTable(light: NonNullable<ImagePlaneSignalScene["image"]["light"]>, wavelengths: readonly number[], surroundReflectance: number, slack: number): {
|
|
73
|
+
table: Float32Array<ArrayBuffer>;
|
|
74
|
+
largestIrradiance: number;
|
|
75
|
+
};
|
|
34
76
|
/** Pass 1's WGSL (see the module comment). */
|
|
35
77
|
export declare function imagePlaneQualityLatticeWgsl(path: ChartCompositeProductPath): string;
|
|
36
78
|
/** Pass 2's WGSL (see the module comment): the blocked sum over the nodes, then the Quality site tail. */
|
|
@@ -40,6 +82,6 @@ export declare const IMAGE_PLANE_QUALITY_SITES_WGSL: string;
|
|
|
40
82
|
* members' span), the lattice extent beyond the site window and the point constants, and the table C_n,c(t) at (n·3 + c)·T + t,
|
|
41
83
|
* the reference's float64 values rounded once.
|
|
42
84
|
*/
|
|
43
|
-
export declare function imagePlaneQualityGather(signalInput: DisplayViewExpectedSignalInput): SignalGather;
|
|
85
|
+
export declare function imagePlaneQualityGather(signalInput: DisplayViewExpectedSignalInput, largestLitRadiance?: number): SignalGather;
|
|
44
86
|
/** The print's Quality passes for a setup (see `DisplayViewQualityImagePasses`), with the double-word product path the device's probe chose. */
|
|
45
87
|
export declare function imagePlaneQualityPasses(runtime: WebGpuRuntime, gpu: DisplayViewGpuSetup, path: ChartCompositeProductPath): DisplayViewQualityImagePasses;
|