@photivra/engine 2.15.0 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +102 -1
- package/CITATION.cff +1 -1
- package/README.md +6 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +38 -0
- package/dist/camera/lens-projection.d.ts +5 -0
- package/dist/camera/lens-projection.js +10 -0
- package/dist/camera/lens-projection.js.map +1 -1
- package/dist/capture/native-environment-lean.js +1 -1
- package/dist/capture/native-environment-lean.js.map +1 -1
- package/dist/capture/native-raw-development.d.ts +15 -0
- package/dist/capture/native-raw-development.js +12 -6
- package/dist/capture/native-raw-development.js.map +1 -1
- package/dist/capture/raw-development-kernel.d.ts +10 -3
- package/dist/capture/raw-development-kernel.js +25 -6
- package/dist/capture/raw-development-kernel.js.map +1 -1
- package/dist/core/internal-radiance-evaluator.d.ts +5 -2
- package/dist/core/internal-radiance-evaluator.js.map +1 -1
- 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/equipment/generic-lens-catalogue.d.ts +227 -0
- package/dist/equipment/generic-lens-catalogue.js +243 -0
- package/dist/equipment/generic-lens-catalogue.js.map +1 -0
- package/dist/facade/defocus-bokeh-zones.d.ts +33 -0
- package/dist/facade/defocus-bokeh-zones.js +53 -0
- package/dist/facade/defocus-bokeh-zones.js.map +1 -0
- package/dist/facade/defocus-image-space-provider.d.ts +118 -0
- package/dist/facade/defocus-image-space-provider.js +448 -0
- package/dist/facade/defocus-image-space-provider.js.map +1 -0
- package/dist/facade/diffraction-provider.d.ts +45 -0
- package/dist/facade/diffraction-provider.js +120 -14
- package/dist/facade/diffraction-provider.js.map +1 -1
- package/dist/facade/display-view-gpu-session.js +4 -0
- package/dist/facade/display-view-gpu-session.js.map +1 -1
- package/dist/facade/display-view-gpu.d.ts +10 -0
- package/dist/facade/display-view-gpu.js.map +1 -1
- package/dist/facade/display-view-lens-signal.d.ts +30 -0
- package/dist/facade/display-view-lens-signal.js +427 -0
- package/dist/facade/display-view-lens-signal.js.map +1 -0
- package/dist/facade/display-view.d.ts +21 -0
- package/dist/facade/display-view.js +66 -8
- package/dist/facade/display-view.js.map +1 -1
- package/dist/facade/expected-signal-setup.d.ts +7 -0
- package/dist/facade/expected-signal-setup.js +12 -2
- package/dist/facade/expected-signal-setup.js.map +1 -1
- package/dist/facade/expected-signal.d.ts +8 -0
- package/dist/facade/expected-signal.js +150 -0
- package/dist/facade/expected-signal.js.map +1 -1
- package/dist/facade/generic-lens-capture.d.ts +6 -0
- package/dist/facade/generic-lens-capture.js +8 -0
- package/dist/facade/generic-lens-capture.js.map +1 -0
- package/dist/facade/large-defocus-lattice.d.ts +39 -0
- package/dist/facade/large-defocus-lattice.js +64 -0
- package/dist/facade/large-defocus-lattice.js.map +1 -0
- package/dist/facade/scene-radiance.d.ts +5 -0
- package/dist/facade/scene-radiance.js +5 -2
- package/dist/facade/scene-radiance.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +148 -6
- package/dist/facade/simulate-capture.js +521 -88
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.js +29 -19
- package/dist/facade/simulate-display-view.js.map +1 -1
- package/dist/gpu/display-view-quality-gpu.d.ts +2 -9
- package/dist/gpu/display-view-quality-gpu.js +63 -13
- package/dist/gpu/display-view-quality-gpu.js.map +1 -1
- package/dist/gpu/display-view-speed-gpu.d.ts +2 -0
- package/dist/gpu/display-view-speed-gpu.js +47 -16
- 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/wgsl-display-view-quality-kernel.d.ts +4 -0
- package/dist/gpu/wgsl-display-view-quality-kernel.js +53 -2
- package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
- package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +15 -0
- package/dist/gpu/wgsl-display-view-speed-kernel.js +42 -1
- package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/optics/defocus-bokeh-kernel.d.ts +207 -0
- package/dist/optics/defocus-bokeh-kernel.js +380 -0
- package/dist/optics/defocus-bokeh-kernel.js.map +1 -0
- package/dist/optics/defocus-disc-kernel.d.ts +44 -21
- package/dist/optics/defocus-disc-kernel.js +47 -25
- package/dist/optics/defocus-disc-kernel.js.map +1 -1
- package/dist/optics/generic-lens-psf.d.ts +68 -0
- package/dist/optics/generic-lens-psf.js +337 -0
- package/dist/optics/generic-lens-psf.js.map +1 -0
- package/dist/optics/illumination-vignetting.d.ts +6 -0
- package/dist/optics/illumination-vignetting.js +24 -7
- package/dist/optics/illumination-vignetting.js.map +1 -1
- package/dist/optics/sensor-environment-query.d.ts +37 -0
- package/dist/optics/sensor-environment-query.js +58 -19
- package/dist/optics/sensor-environment-query.js.map +1 -1
- package/dist/optics/site-kernel-runs.d.ts +77 -0
- package/dist/optics/site-kernel-runs.js +200 -0
- package/dist/optics/site-kernel-runs.js.map +1 -0
- package/dist/output/generic-lens-corrections.d.ts +24 -0
- package/dist/output/generic-lens-corrections.js +51 -0
- package/dist/output/generic-lens-corrections.js.map +1 -0
- package/dist/processing/development-detail.d.ts +132 -0
- package/dist/processing/development-detail.js +325 -0
- package/dist/processing/development-detail.js.map +1 -0
- package/docs/AGENT_GUIDE.md +1 -0
- package/docs/API_REFERENCE.md +54 -1
- package/docs/QUICK_START.md +444 -26
- package/docs/USAGE.md +71 -8
- package/docs/api/capture-native-raw-development.md +16 -0
- package/docs/api/core-version.md +1 -1
- package/docs/api/equipment-generic-lens-catalogue.md +281 -0
- package/docs/api/exports.json +162 -2
- package/docs/api/facade-simulate-capture.md +151 -5
- package/docs/api/optics-defocus-bokeh-kernel.md +145 -0
- package/docs/api/optics-defocus-disc-kernel.md +25 -17
- package/docs/api/optics-sensor-environment-query.md +6 -0
- package/docs/api/output-generic-lens-corrections.md +39 -0
- package/llms.txt +1 -0
- package/package.json +1 -1
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* reference, so they are exact. Every stage's wall-clock time is reported (`stageMilliseconds`); on a software adapter it
|
|
26
26
|
* is not GPU performance.
|
|
27
27
|
*/
|
|
28
|
-
import { AHD_KEY_LEVELS, EXACT_AREA_MEAN_MAX_PIXELS, axisSums, computeDisplayViewCorrectionStates, createDisplayViewExpectedSignal, displayViewCorrectionKey, overlaps, renderDisplayView, ahdCandidateKernels } from "../facade/display-view.js";
|
|
28
|
+
import { AHD_KEY_LEVELS, EXACT_AREA_MEAN_MAX_PIXELS, axisSums, computeDisplayViewCorrectionStates, createDisplayViewExpectedSignal, displayViewCorrectionKey, displayViewDecidedSaturation, overlaps, renderDisplayView, ahdCandidateKernels } from "../facade/display-view.js";
|
|
29
29
|
import { displayViewSignalTables } from "../facade/expected-signal.js";
|
|
30
30
|
import { resolvePortableChartScene } from "../facade/chart-scenes.js";
|
|
31
31
|
import { createDisplayViewMaterialModules } from "./display-view-composite-material-module.js";
|
|
@@ -36,7 +36,7 @@ import { createHostYieldGate } from "../capture/host-yield-cadence.js";
|
|
|
36
36
|
import { createDefocusDiscSiteKernel } from "../optics/defocus-disc-kernel.js";
|
|
37
37
|
import { ImageKernelExecutionError, WEBGPU_F32_UNIT_ROUNDOFF, webGpuExecution } from "./image-kernel-execution.js";
|
|
38
38
|
import { BUFFER_USAGE, GpuResourceScope, abortedError, createComputePipeline, linearDispatch, runComputePass } from "./webgpu-runtime.js";
|
|
39
|
-
import { DISPLAY_VIEW_QUALITY_AUX, DISPLAY_VIEW_QUALITY_BITMAP_WORDS, DISPLAY_VIEW_QUALITY_CANDIDATE_ENTRIES, DISPLAY_VIEW_QUALITY_CANDIDATE_FLOATS, DISPLAY_VIEW_QUALITY_FLAG, DISPLAY_VIEW_QUALITY_GEOMETRY_STRIDE, DISPLAY_VIEW_QUALITY_GROUP_WORDS, DISPLAY_VIEW_QUALITY_MAXIMUM_PIXELS_PER_AXIS, DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS, DISPLAY_VIEW_QUALITY_PARAM_WORDS, DISPLAY_VIEW_QUALITY_PIXELS_WGSL, DISPLAY_VIEW_QUALITY_SITES_BLOCKED_WGSL, DISPLAY_VIEW_QUALITY_SITES_WGSL, DISPLAY_VIEW_QUALITY_SITE_FLOATS, DISPLAY_VIEW_QUALITY_TAP_WORDS, DISPLAY_VIEW_QUALITY_WORKGROUP_SIZE, assembleDisplayViewQualityLatticeWgsl } from "./wgsl-display-view-quality-kernel.js";
|
|
39
|
+
import { DISPLAY_VIEW_QUALITY_AUX, DISPLAY_VIEW_QUALITY_BITMAP_WORDS, DISPLAY_VIEW_QUALITY_CANDIDATE_ENTRIES, DISPLAY_VIEW_QUALITY_CANDIDATE_FLOATS, DISPLAY_VIEW_QUALITY_FLAG, DISPLAY_VIEW_QUALITY_FLAG_WORDS, DISPLAY_VIEW_QUALITY_GEOMETRY_STRIDE, DISPLAY_VIEW_QUALITY_GROUP_WORDS, DISPLAY_VIEW_QUALITY_MAXIMUM_PIXELS_PER_AXIS, DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS, DISPLAY_VIEW_QUALITY_PARAM_WORDS, DISPLAY_VIEW_QUALITY_PIXELS_WGSL, DISPLAY_VIEW_QUALITY_SITES_BLOCKED_WGSL, DISPLAY_VIEW_QUALITY_SITES_WGSL, DISPLAY_VIEW_QUALITY_SITE_FLOATS, DISPLAY_VIEW_QUALITY_TAP_WORDS, DISPLAY_VIEW_QUALITY_WORKGROUP_SIZE, assembleDisplayViewQualityLatticeWgsl } from "./wgsl-display-view-quality-kernel.js";
|
|
40
40
|
/** One WGSL rounding of + − × in either direction (W3C WGSL "Floating Point Accuracy"; #471, #487): twice the binary32 unit roundoff. */
|
|
41
41
|
const E = 2 * WEBGPU_F32_UNIT_ROUNDOFF;
|
|
42
42
|
/** Every reported bound is doubled: the kernel's running bounds are first order, and their own float32 arithmetic rounds. */
|
|
@@ -74,7 +74,7 @@ const WINDOW_SLOTS = (2 * MAXIMUM_REACH + 1) ** 2;
|
|
|
74
74
|
*/
|
|
75
75
|
const QUANTIZATION_SLOPE = 6.04, QUANTIZATION_JOIN_JUMP = 2.1e-4, QUANTIZATION_JOIN = 0.0031308;
|
|
76
76
|
/** Bytes per display pixel in the output buffers (moments plus the flag word). */
|
|
77
|
-
const OUTPUT_BYTES_PER_PIXEL = 4 * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS + 4;
|
|
77
|
+
const OUTPUT_BYTES_PER_PIXEL = 4 * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS + 4 * DISPLAY_VIEW_QUALITY_FLAG_WORDS;
|
|
78
78
|
const SITE_BYTES = 4 * DISPLAY_VIEW_QUALITY_SITE_FLOATS;
|
|
79
79
|
/**
|
|
80
80
|
* The low-signal correction states a renderer holds for one correction key, as the GPU table reads them: grid keys ascending
|
|
@@ -156,6 +156,8 @@ function exactLatticeConstant(c, span) {
|
|
|
156
156
|
* 2·reach + 2 sites on each axis (so a reflected border site lies in the band's window).
|
|
157
157
|
*/
|
|
158
158
|
export function displayViewQualityGpuUnsupportedReason(setup, signalInput) {
|
|
159
|
+
if (signalInput.largeKernel)
|
|
160
|
+
return LARGE_DEFOCUS_REASON;
|
|
159
161
|
if (signalInput.scene.kind !== "materials")
|
|
160
162
|
return "radiance scenes (caller functions) are not on the GPU";
|
|
161
163
|
if (!signalInput.kernels && !signalInput.queryPoint)
|
|
@@ -533,7 +535,7 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
|
|
|
533
535
|
const sitesPipeline = blocked ? await pipelines("photivra-display-view-quality-sites-blocked", DISPLAY_VIEW_QUALITY_SITES_BLOCKED_WGSL) :
|
|
534
536
|
await pipelines("photivra-display-view-quality-sites", DISPLAY_VIEW_QUALITY_SITES_WGSL);
|
|
535
537
|
const pixelsPipeline = await pipelines("photivra-display-view-quality-pixels", DISPLAY_VIEW_QUALITY_PIXELS_WGSL);
|
|
536
|
-
const moments = new Float32Array(pixelCount * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS), pixelFlags = new Uint32Array(pixelCount);
|
|
538
|
+
const moments = new Float32Array(pixelCount * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS), pixelFlags = new Uint32Array(pixelCount), masks = new Uint32Array(2 * pixelCount);
|
|
537
539
|
const states = input.states ?? new CorrectionStateStore(), correction = setup.ahdCorrection ? correctionSetup(setup) : null;
|
|
538
540
|
let statesComputed = 0, latticePointsResolved = 0;
|
|
539
541
|
const scope = new GpuResourceScope(runtime);
|
|
@@ -628,7 +630,7 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
|
|
|
628
630
|
// Pass 3: display pixels, repeated once when a correction state was missing and has been computed.
|
|
629
631
|
words[0] = count;
|
|
630
632
|
const out = band.buffer("photivra-display-view-moments", count * 4 * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS, BUFFER_USAGE.STORAGE | BUFFER_USAGE.COPY_SRC);
|
|
631
|
-
const flagBuffer = band.buffer("photivra-display-view-flags", count * 4, BUFFER_USAGE.STORAGE | BUFFER_USAGE.COPY_SRC);
|
|
633
|
+
const flagBuffer = band.buffer("photivra-display-view-flags", count * 4 * DISPLAY_VIEW_QUALITY_FLAG_WORDS, BUFFER_USAGE.STORAGE | BUFFER_USAGE.COPY_SRC);
|
|
632
634
|
const bitmapBuffer = band.buffer("photivra-display-view-bitmap", 4 * DISPLAY_VIEW_QUALITY_BITMAP_WORDS, BUFFER_USAGE.STORAGE | BUFFER_USAGE.COPY_SRC);
|
|
633
635
|
for (let attempt = 0;; attempt++) {
|
|
634
636
|
checkAbort(abort.signal);
|
|
@@ -646,13 +648,15 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
|
|
|
646
648
|
{ binding: 3, resource: { buffer: siteBuffer } }, { binding: 4, resource: { buffer: keysBuffer } }, { binding: 5, resource: { buffer: valuesBuffer } },
|
|
647
649
|
{ binding: 6, resource: { buffer: bitmapBuffer } }, { binding: 7, resource: { buffer: out } }, { binding: 8, resource: { buffer: flagBuffer } }
|
|
648
650
|
] });
|
|
649
|
-
[data, flagData, bitmapData] = await runComputePass(runtime, pass, pixelsPipeline, pixelGroup, linearDispatch(count, DISPLAY_VIEW_QUALITY_WORKGROUP_SIZE, runtime.maximumWorkgroupsPerDimension), [{ buffer: out, bytes: count * 4 * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS }, { buffer: flagBuffer, bytes: count * 4 }, { buffer: bitmapBuffer, bytes: 4 * DISPLAY_VIEW_QUALITY_BITMAP_WORDS }], abort.signal);
|
|
651
|
+
[data, flagData, bitmapData] = await runComputePass(runtime, pass, pixelsPipeline, pixelGroup, linearDispatch(count, DISPLAY_VIEW_QUALITY_WORKGROUP_SIZE, runtime.maximumWorkgroupsPerDimension), [{ buffer: out, bytes: count * 4 * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS }, { buffer: flagBuffer, bytes: count * 4 * DISPLAY_VIEW_QUALITY_FLAG_WORDS }, { buffer: bitmapBuffer, bytes: 4 * DISPLAY_VIEW_QUALITY_BITMAP_WORDS }], abort.signal);
|
|
650
652
|
}
|
|
651
653
|
finally {
|
|
652
654
|
pass.release();
|
|
653
655
|
}
|
|
654
656
|
timings.pixels += now() - t0;
|
|
655
|
-
const
|
|
657
|
+
const flagWords = new Uint32Array(flagData, 0, count * DISPLAY_VIEW_QUALITY_FLAG_WORDS), bandFlags = new Uint32Array(count);
|
|
658
|
+
for (let i = 0; i < count; i++)
|
|
659
|
+
bandFlags[i] = flagWords[DISPLAY_VIEW_QUALITY_FLAG_WORDS * i];
|
|
656
660
|
let missing = false;
|
|
657
661
|
for (let i = 0; i < count && !missing; i++)
|
|
658
662
|
if ((bandFlags[i] & DISPLAY_VIEW_QUALITY_FLAG.stateMissing) !== 0)
|
|
@@ -683,6 +687,10 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
|
|
|
683
687
|
}
|
|
684
688
|
moments.set(new Float32Array(data, 0, count * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS), first * DISPLAY_VIEW_QUALITY_OUTPUT_FLOATS);
|
|
685
689
|
pixelFlags.set(bandFlags, first);
|
|
690
|
+
for (let i = 0; i < count; i++) {
|
|
691
|
+
masks[2 * (first + i)] = flagWords[DISPLAY_VIEW_QUALITY_FLAG_WORDS * i + 1];
|
|
692
|
+
masks[2 * (first + i) + 1] = flagWords[DISPLAY_VIEW_QUALITY_FLAG_WORDS * i + 2];
|
|
693
|
+
}
|
|
686
694
|
break;
|
|
687
695
|
}
|
|
688
696
|
}
|
|
@@ -703,11 +711,18 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
|
|
|
703
711
|
let t0 = now();
|
|
704
712
|
const maximum = setup.bitDepth === 8 ? 255 : 65535, step = 1 / maximum;
|
|
705
713
|
const samples = setup.bitDepth === 8 ? new Uint8Array(pixelCount * 3) : new Uint16Array(pixelCount * 3);
|
|
706
|
-
const expected = new Float64Array(pixelCount * 3), noiseStd = new Float64Array(pixelCount * 3);
|
|
714
|
+
const expected = new Float64Array(pixelCount * 3), noiseStd = new Float64Array(pixelCount * 3), saturated = new Float64Array(pixelCount);
|
|
707
715
|
const meanBound = new Float32Array(pixelCount), varianceBound = new Float32Array(pixelCount);
|
|
708
716
|
const flagged = [];
|
|
709
717
|
let largestMean = 0, largestVariance = 0, sampleCount = 0, siteCount = 0, corrected = 0;
|
|
710
718
|
const counts = new Int32Array(geometry.buffer);
|
|
719
|
+
// #533: each display pixel's saturated-pixel share from the kernel's mask (the reference's arithmetic, exact where it decided).
|
|
720
|
+
const columnOverlaps = Array.from({ length: region.width }, (_, i) => overlaps((region.x + i) * shape.sx, (region.x + i + 1) * shape.sx, setup.frameWidth));
|
|
721
|
+
for (let ry = 0, i = 0; ry < region.height; ry++) {
|
|
722
|
+
const rowOverlaps = overlaps((region.y + ry) * shape.sy, (region.y + ry + 1) * shape.sy, setup.frameHeight);
|
|
723
|
+
for (let rx = 0; rx < region.width; rx++, i++)
|
|
724
|
+
saturated[i] = displayViewDecidedSaturation(columnOverlaps[rx], rowOverlaps, area, masks[2 * i], masks[2 * i + 1]);
|
|
725
|
+
}
|
|
711
726
|
for (let ry = 0, i = 0; ry < region.height; ry++) {
|
|
712
727
|
const rowWw = rowSums[ry].ww, ny = counts[(region.width + ry) * stride + 1];
|
|
713
728
|
for (let rx = 0; rx < region.width; rx++, i++) {
|
|
@@ -735,7 +750,30 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
|
|
|
735
750
|
timings.finishing = now() - t0;
|
|
736
751
|
// Flagged display pixels: the reference's own pixels (a region render is byte-identical to the whole view's pixels).
|
|
737
752
|
t0 = now();
|
|
738
|
-
const recomputed = [];
|
|
753
|
+
const recomputed = [], highlights = [];
|
|
754
|
+
// #533: unflagged display pixels with an undecided real pixel take the reference's count only (their samples stay the kernel's).
|
|
755
|
+
const undecided = [], isFlagged = new Uint8Array(pixelCount);
|
|
756
|
+
for (const i of flagged)
|
|
757
|
+
isFlagged[i] = 1;
|
|
758
|
+
for (let i = 0; i < pixelCount; i++)
|
|
759
|
+
if (isFlagged[i] === 0 && (pixelFlags[i] & DISPLAY_VIEW_QUALITY_FLAG.highlightUndecided) !== 0)
|
|
760
|
+
undecided.push(i);
|
|
761
|
+
if (undecided.length > 0 && input.recomputeFlagged !== false) {
|
|
762
|
+
const signal = createDisplayViewExpectedSignal(signalInput);
|
|
763
|
+
for (let r = 0; r < undecided.length;) {
|
|
764
|
+
checkAbort(abort.signal);
|
|
765
|
+
const first = undecided[r], rx = first % region.width, ry = (first - rx) / region.width;
|
|
766
|
+
let run = 1;
|
|
767
|
+
while (r + run < undecided.length && undecided[r + run] === first + run && rx + run < region.width)
|
|
768
|
+
run++;
|
|
769
|
+
const part = await renderDisplayView({ ...setup, signal, region: { x: region.x + rx, y: region.y + ry, width: run, height: 1 } });
|
|
770
|
+
for (let k = 0; k < run; k++) {
|
|
771
|
+
saturated[first + k] = part.saturated[k];
|
|
772
|
+
highlights.push(first + k);
|
|
773
|
+
}
|
|
774
|
+
r += run;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
739
777
|
if (flagged.length > 0) {
|
|
740
778
|
if (input.recomputeFlagged === false) {
|
|
741
779
|
// Without recomputation a flagged pixel keeps the kernel's values where they are finite (its bound then does not hold).
|
|
@@ -768,6 +806,7 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
|
|
|
768
806
|
samples.set(part.samples, first * 3);
|
|
769
807
|
expected.set(part.expected, first * 3);
|
|
770
808
|
noiseStd.set(part.noiseStd, first * 3);
|
|
809
|
+
saturated.set(part.saturated, first);
|
|
771
810
|
for (let k = 0; k < run; k++) {
|
|
772
811
|
meanBound[first + k] = 0;
|
|
773
812
|
varianceBound[first + k] = 0;
|
|
@@ -783,11 +822,14 @@ export async function renderDisplayViewQualityOnGpu(runtime, bandBytes, input, a
|
|
|
783
822
|
timings.recompute = now() - t0;
|
|
784
823
|
const relative = MARGIN * CPU_RELATIVE;
|
|
785
824
|
const expectedValueBound = { kind: "relative-to-reference", relative, absolute: largestMean };
|
|
786
|
-
const uncertain = flagged.length - recomputed.length;
|
|
787
|
-
|
|
825
|
+
const uncertain = flagged.length - recomputed.length + undecided.length - highlights.length;
|
|
826
|
+
let saturatedPixelCount = 0;
|
|
827
|
+
for (let i = 0; i < pixelCount; i++)
|
|
828
|
+
saturatedPixelCount += saturated[i];
|
|
829
|
+
return { samples, expected, noiseStd, sampleCount, siteCount, detailPixelCount: pixelCount, uniformPixelCount: 0, ahdCorrectedPixelCount: corrected, estimation: "exact-area-mean", saturated, saturatedPixelCount,
|
|
788
830
|
execution: webGpuExecution(expectedValueBound, uncertain), expectedValueBound, varianceBound: { kind: "relative-to-reference", relative, absolute: largestVariance },
|
|
789
831
|
expectedValueAbsoluteBound: meanBound, varianceAbsoluteBound: varianceBound, flaggedPixelIndices: Uint32Array.from(flagged), hostRecomputedPixelIndices: Uint32Array.from(recomputed),
|
|
790
|
-
pixelFlags, statesComputed, statesHeld: states.size, tapsPerSite: gather.tapCount, blockedSum: blocked, siteSumRelativeBound: floats[50], latticePointsResolved, stageMilliseconds: timings };
|
|
832
|
+
pixelFlags, highlightRecomputedPixelIndices: Uint32Array.from(highlights), statesComputed, statesHeld: states.size, tapsPerSite: gather.tapCount, blockedSum: blocked, siteSumRelativeBound: floats[50], latticePointsResolved, stageMilliseconds: timings };
|
|
791
833
|
}
|
|
792
834
|
/**
|
|
793
835
|
* The GPU setup the material modules read for a Quality render (#491's `createDisplayViewMaterialModules`). The composite module
|
|
@@ -909,6 +951,9 @@ async function runQualityConformance(handle, signal, defocus) {
|
|
|
909
951
|
if (Math.abs(gpu.samples[i] - reference.samples[i]) > 1)
|
|
910
952
|
return "component " + i + ": sample " + gpu.samples[i] + " differs from the reference " + reference.samples[i] + " by more than one code.";
|
|
911
953
|
}
|
|
954
|
+
// #533: the saturated-pixel count is the reference's, bit for bit (the light squares sit at the white clip).
|
|
955
|
+
if (gpu.saturatedPixelCount !== reference.saturatedPixelCount)
|
|
956
|
+
return "the saturated-pixel count " + gpu.saturatedPixelCount + " differs from the reference's " + reference.saturatedPixelCount + ".";
|
|
912
957
|
return true;
|
|
913
958
|
}
|
|
914
959
|
finally {
|
|
@@ -936,6 +981,8 @@ function bilinearKernels() {
|
|
|
936
981
|
* carries the expected signal's input and the chart; a setup without it, a coarse view or a frame the kernels do not cover
|
|
937
982
|
* throws `unsupported-on-backend`), and throws `aborted` and `device-lost` as the accelerator's operations do.
|
|
938
983
|
*/
|
|
984
|
+
/** #564: the GPU refusal of a defocus kernel above the direct radius (the CPU convolves it by runs). */
|
|
985
|
+
const LARGE_DEFOCUS_REASON = "a defocus kernel radius above 64 sites (convolved by runs on the CPU, #564) is not on the GPU";
|
|
939
986
|
export function createDisplayViewGpuRenderer(runtime, options = {}) {
|
|
940
987
|
const pipelines = new Map(), stores = new Map();
|
|
941
988
|
const bandBytes = options.maximumBandBytes ?? Math.min(64 * 1024 * 1024, runtime.maximumStorageBindingBytes);
|
|
@@ -954,6 +1001,8 @@ export function createDisplayViewGpuRenderer(runtime, options = {}) {
|
|
|
954
1001
|
return {
|
|
955
1002
|
id: "photivra-display-view",
|
|
956
1003
|
supports(request) {
|
|
1004
|
+
if (request.largeDefocus)
|
|
1005
|
+
return LARGE_DEFOCUS_REASON;
|
|
957
1006
|
// #492: out of focus the expected signal carries the defocus disc as site kernels, which only the Quality site pass gathers;
|
|
958
1007
|
// a Speed request then runs the Quality passes with its own bilinear demosaic (one candidate) and finishing.
|
|
959
1008
|
if (request.defocus)
|
|
@@ -991,7 +1040,8 @@ export function createDisplayViewGpuRenderer(runtime, options = {}) {
|
|
|
991
1040
|
result = await renderDisplayViewQualityOnGpu(runtime, bandBytes, { setup, signalInput, material, ...(states ? { states } : {}) }, abort, options.yieldControl, source);
|
|
992
1041
|
}
|
|
993
1042
|
return { samples: result.samples, expected: result.expected, noiseStd: result.noiseStd, sampleCount: result.sampleCount, siteCount: result.siteCount, detailPixelCount: result.detailPixelCount,
|
|
994
|
-
uniformPixelCount: result.uniformPixelCount, ahdCorrectedPixelCount: result.ahdCorrectedPixelCount, estimation: result.estimation,
|
|
1043
|
+
uniformPixelCount: result.uniformPixelCount, ahdCorrectedPixelCount: result.ahdCorrectedPixelCount, estimation: result.estimation, saturated: result.saturated,
|
|
1044
|
+
saturatedPixelCount: result.saturatedPixelCount, errorBound: result.expectedValueBound,
|
|
995
1045
|
diagnosticUncertaintySampleCount: result.execution.diagnosticUncertaintySampleCount, ...(material.compositeProbe ? { compositeProbe: material.compositeProbe } : {}) };
|
|
996
1046
|
}
|
|
997
1047
|
finally {
|