@photivra/engine 2.20.0 → 2.22.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 +295 -1
- package/CITATION.cff +1 -1
- package/README.md +7 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +18 -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-lens-correction-opcodes.d.ts +2 -2
- package/dist/capture/dng-lens-correction-opcodes.js +2 -2
- package/dist/capture/dng-lens-correction-opcodes.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/exposure-build-up-stage.d.ts +16 -0
- package/dist/capture/exposure-build-up-stage.js +4 -0
- package/dist/capture/exposure-build-up-stage.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-environment-lean.d.ts +2 -1
- package/dist/capture/native-environment-lean.js +41 -73
- package/dist/capture/native-environment-lean.js.map +1 -1
- package/dist/capture/native-environment-tabulated.js +4 -3
- package/dist/capture/native-environment-tabulated.js.map +1 -1
- package/dist/capture/native-raw-development.d.ts +2 -1
- package/dist/capture/native-raw-development.js.map +1 -1
- package/dist/capture/native-raw.d.ts +3 -2
- package/dist/capture/native-raw.js +5 -4
- package/dist/capture/native-raw.js.map +1 -1
- package/dist/capture/sensor-raw-producer.d.ts +4 -1
- package/dist/capture/sensor-raw-producer.js +12 -3
- package/dist/capture/sensor-raw-producer.js.map +1 -1
- package/dist/color/neighbor-highlight-reconstruction.d.ts +66 -0
- package/dist/color/neighbor-highlight-reconstruction.js +234 -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/equipment/generic-lens-catalogue.d.ts +3 -2
- package/dist/equipment/generic-lens-catalogue.js +18 -5
- package/dist/equipment/generic-lens-catalogue.js.map +1 -1
- package/dist/equipment/generic-tier-assets.d.ts +32 -0
- package/dist/equipment/generic-tier-assets.js +16 -11
- package/dist/equipment/generic-tier-assets.js.map +1 -1
- package/dist/equipment/sensor-profile-body.d.ts +78 -0
- package/dist/equipment/sensor-profile-body.js +77 -0
- package/dist/equipment/sensor-profile-body.js.map +1 -0
- package/dist/equipment/sensor-profiles.d.ts +8 -0
- package/dist/equipment/sensor-profiles.js +82 -0
- package/dist/equipment/sensor-profiles.js.map +1 -0
- package/dist/facade/catalogue-lens-signal.d.ts +28 -3
- package/dist/facade/catalogue-lens-signal.js +83 -78
- package/dist/facade/catalogue-lens-signal.js.map +1 -1
- package/dist/facade/chart-radiance-batch.js +2 -1
- package/dist/facade/chart-radiance-batch.js.map +1 -1
- package/dist/facade/defocus-image-space-provider.d.ts +7 -0
- package/dist/facade/defocus-image-space-provider.js +64 -76
- package/dist/facade/defocus-image-space-provider.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 +39 -5
- package/dist/facade/display-view-gpu-session.js.map +1 -1
- package/dist/facade/display-view-gpu.d.ts +19 -6
- package/dist/facade/display-view-gpu.js.map +1 -1
- package/dist/facade/display-view-lens-signal.js +25 -23
- package/dist/facade/display-view-lens-signal.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 +97 -0
- package/dist/facade/display-view-rendering.js +598 -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 +152 -499
- package/dist/facade/display-view.js.map +1 -1
- package/dist/facade/expected-signal-setup.d.ts +3 -1
- package/dist/facade/expected-signal-setup.js +3 -3
- package/dist/facade/expected-signal-setup.js.map +1 -1
- package/dist/facade/expected-signal.d.ts +47 -14
- package/dist/facade/expected-signal.js +117 -112
- package/dist/facade/expected-signal.js.map +1 -1
- package/dist/facade/exposure-build-up.d.ts +70 -0
- package/dist/facade/exposure-build-up.js +164 -0
- package/dist/facade/exposure-build-up.js.map +1 -0
- package/dist/facade/fast-methods.d.ts +1 -1
- package/dist/facade/fast-methods.js +46 -9
- package/dist/facade/fast-methods.js.map +1 -1
- package/dist/facade/generic-lens-capture.d.ts +3 -3
- package/dist/facade/generic-lens-capture.js +3 -3
- package/dist/facade/generic-lens-capture.js.map +1 -1
- package/dist/facade/image-plane-enable.d.ts +7 -0
- package/dist/facade/image-plane-enable.js +17 -0
- package/dist/facade/image-plane-enable.js.map +1 -0
- package/dist/facade/image-plane-lattice-data.d.ts +6 -0
- package/dist/facade/image-plane-lattice-data.js +10 -0
- package/dist/facade/image-plane-lattice-data.js.map +1 -0
- package/dist/facade/image-plane-support.d.ts +33 -0
- package/dist/facade/image-plane-support.js +11 -0
- package/dist/facade/image-plane-support.js.map +1 -0
- package/dist/facade/image-plane.d.ts +36 -0
- package/dist/facade/image-plane.js +384 -0
- package/dist/facade/image-plane.js.map +1 -0
- package/dist/facade/mixed-illumination.d.ts +108 -0
- package/dist/facade/mixed-illumination.js +174 -0
- package/dist/facade/mixed-illumination.js.map +1 -0
- 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/representative-light-sources.d.ts +72 -0
- package/dist/facade/representative-light-sources.js +124 -0
- package/dist/facade/representative-light-sources.js.map +1 -0
- package/dist/facade/scene-radiance.d.ts +145 -4
- package/dist/facade/scene-radiance.js +50 -13
- package/dist/facade/scene-radiance.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +68 -20
- package/dist/facade/simulate-capture.js +399 -146
- 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 +70 -53
- package/dist/facade/simulate-display-view.js.map +1 -1
- package/dist/gpu/chart-composite-gpu.d.ts +13 -1
- package/dist/gpu/chart-composite-gpu.js +48 -9
- package/dist/gpu/chart-composite-gpu.js.map +1 -1
- package/dist/gpu/chart-radiance-gpu.js +4 -30
- package/dist/gpu/chart-radiance-gpu.js.map +1 -1
- package/dist/gpu/display-view-composite-material-module.d.ts +10 -4
- package/dist/gpu/display-view-composite-material-module.js +39 -13
- package/dist/gpu/display-view-composite-material-module.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 +87 -0
- package/dist/gpu/display-view-image-material-module.js +361 -0
- package/dist/gpu/display-view-image-material-module.js.map +1 -0
- package/dist/gpu/display-view-image-quality.d.ts +87 -0
- package/dist/gpu/display-view-image-quality.js +625 -0
- package/dist/gpu/display-view-image-quality.js.map +1 -0
- package/dist/gpu/display-view-quality-gpu.d.ts +80 -65
- package/dist/gpu/display-view-quality-gpu.js +187 -445
- package/dist/gpu/display-view-quality-gpu.js.map +1 -1
- package/dist/gpu/display-view-speed-gpu.d.ts +67 -19
- package/dist/gpu/display-view-speed-gpu.js +181 -105
- 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 +8 -0
- package/dist/gpu/wgsl-display-view-coupled-stub.js +21 -0
- package/dist/gpu/wgsl-display-view-coupled-stub.js.map +1 -0
- package/dist/gpu/wgsl-display-view-coupled.d.ts +88 -0
- package/dist/gpu/wgsl-display-view-coupled.js +353 -0
- package/dist/gpu/wgsl-display-view-coupled.js.map +1 -0
- package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +33 -24
- package/dist/gpu/wgsl-display-view-quality-kernel.js +166 -146
- package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
- package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +19 -44
- package/dist/gpu/wgsl-display-view-speed-kernel.js +116 -18
- package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
- package/dist/gpu/wgsl-exact-sum.d.ts +20 -0
- package/dist/gpu/wgsl-exact-sum.js +42 -0
- package/dist/gpu/wgsl-exact-sum.js.map +1 -0
- package/dist/index.d.ts +22 -6
- package/dist/index.js +16 -2
- package/dist/index.js.map +1 -1
- package/dist/motion/subject-motion.d.ts +66 -0
- package/dist/motion/subject-motion.js +52 -0
- package/dist/motion/subject-motion.js.map +1 -0
- package/dist/optics/generic-lens-lateral-color.d.ts +83 -0
- package/dist/optics/generic-lens-lateral-color.js +77 -0
- package/dist/optics/generic-lens-lateral-color.js.map +1 -0
- package/dist/optics/generic-lens-psf.js +54 -46
- package/dist/optics/generic-lens-psf.js.map +1 -1
- package/dist/optics/lens-psf-profile.d.ts +7 -0
- package/dist/optics/lens-psf-profile.js +2 -1
- package/dist/optics/lens-psf-profile.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/developed-lens-corrections.d.ts +19 -5
- package/dist/output/developed-lens-corrections.js +28 -9
- package/dist/output/developed-lens-corrections.js.map +1 -1
- package/dist/output/generic-lens-corrections.d.ts +41 -5
- package/dist/output/generic-lens-corrections.js +52 -8
- package/dist/output/generic-lens-corrections.js.map +1 -1
- package/dist/output/native-capture-sdr.js +5 -2
- package/dist/output/native-capture-sdr.js.map +1 -1
- package/dist/output/print-plan.d.ts +41 -5
- package/dist/output/print-plan.js +59 -14
- package/dist/output/print-plan.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/binomial-sample.d.ts +3 -0
- package/dist/sensor/binomial-sample.js +86 -0
- package/dist/sensor/binomial-sample.js.map +1 -0
- 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 +91 -13
- package/dist/sensor/sensor-characteristics.js +30 -15
- package/dist/sensor/sensor-characteristics.js.map +1 -1
- package/docs/AGENT_GUIDE.md +1 -0
- package/docs/API_REFERENCE.md +214 -4
- package/docs/QUICK_START.md +162 -8
- package/docs/USAGE.md +195 -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/equipment-generic-lens-catalogue.md +10 -5
- package/docs/api/equipment-sensor-profile-body.md +64 -0
- package/docs/api/equipment-sensor-profiles.md +86 -0
- package/docs/api/exports.json +460 -5
- package/docs/api/facade-display-view-gpu.md +5 -2
- package/docs/api/facade-display-view.md +11 -15
- package/docs/api/facade-exposure-build-up.md +105 -0
- package/docs/api/facade-fast-methods.md +47 -10
- package/docs/api/facade-image-plane-enable.md +16 -0
- package/docs/api/facade-mixed-illumination.md +67 -0
- package/docs/api/facade-quality-paths.md +24 -0
- package/docs/api/facade-representative-light-sources.md +131 -0
- package/docs/api/facade-scene-radiance.md +54 -3
- package/docs/api/facade-simulate-capture.md +48 -11
- package/docs/api/facade-simulate-display-view.md +10 -12
- package/docs/api/gpu-image-kernel-execution.md +0 -36
- package/docs/api/motion-subject-motion.md +23 -0
- package/docs/api/optics-generic-lens-lateral-color.md +79 -0
- package/docs/api/output-camera-channel-response.md +55 -0
- package/docs/api/output-developed-lens-corrections.md +10 -1
- package/docs/api/output-generic-lens-corrections.md +40 -4
- package/docs/api/output-print-plan.md +35 -1
- package/docs/api/output-sdr-rendering.md +6 -1
- package/docs/api/sensor-sensor-characteristics.md +54 -2
- package/llms.txt +3 -0
- package/package.json +6 -5
|
@@ -1,22 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* `DISPLAY_VIEW_SPEED_KERNEL_WGSL`, and the finishing the CPU reference does after its per-sample loop: the output
|
|
5
|
-
* quantization term, the seeded noise draw, the Cholesky factor, the clipped-normal centre, the sRGB encode and the
|
|
6
|
-
* rounding, all with the reference's own float64 functions. So the noise draw is bit-identical to the CPU's, and only
|
|
7
|
-
* the expected value and the covariance carry the float32 bound.
|
|
8
|
-
*
|
|
9
|
-
* The float64 reference is `renderDisplayView` (facade/display-view.ts) on the exact-area-mean path without
|
|
10
|
-
* diffraction, with the bilinear demosaic and chart materials. Internal: not exported from the package. The
|
|
11
|
-
* material lookup per query point is a module the caller supplies (`DisplayViewGpuMaterialModule`, the seam of
|
|
12
|
-
* #477); `display-view-chart-material-module.ts` provides one for the eight 2.0 chart presets and
|
|
13
|
-
* `display-view-composite-material-module.ts` (#491) one for composite charts, the 2.3 elements and `material-layers` scenes.
|
|
14
|
-
*/
|
|
15
|
-
import { type DisplayViewRenderResult, type DisplayViewSetup } from "../facade/display-view.js";
|
|
16
|
-
import type { DisplayViewExpectedSignalInput } from "../facade/expected-signal.js";
|
|
1
|
+
import { type DisplayViewKernelTap, type DisplayViewRenderResult, type DisplayViewSetup } from "../facade/display-view.js";
|
|
2
|
+
import { type DisplayViewExpectedSignalInput } from "../facade/expected-signal.js";
|
|
3
|
+
import { resolvePortableChartScene } from "../facade/chart-scenes.js";
|
|
17
4
|
import { type DisplayViewGpuConformanceCase, type DisplayViewGpuRenderer, type DisplayViewGpuRendererFactory, type DisplayViewGpuRequest } from "../facade/display-view-gpu.js";
|
|
18
5
|
import { type ChartCompositeProbeRecord, type ImageKernelExecution, type ImageKernelRelativeErrorBound } from "./image-kernel-execution.js";
|
|
19
|
-
import { type WebGpuRuntime } from "./webgpu-runtime.js";
|
|
6
|
+
import { GpuResourceScope, type WebGpuRuntime } from "./webgpu-runtime.js";
|
|
20
7
|
type PipelineSource = (label: string, code: string) => Promise<GPUComputePipeline>;
|
|
21
8
|
type YieldControl = ((signal: AbortSignal) => Promise<void>) | undefined;
|
|
22
9
|
/**
|
|
@@ -47,6 +34,18 @@ export interface DisplayViewGpuMaterialModule {
|
|
|
47
34
|
buffer: GPUBuffer;
|
|
48
35
|
data?: undefined;
|
|
49
36
|
})[];
|
|
37
|
+
/**
|
|
38
|
+
* #581: a module that defines `scene_value` itself (the image-plane module) states the roundings its value carries beyond the
|
|
39
|
+
* table lookup's one, added to the mean's and (doubled) the variance's chains; and it gives the data of the kernel's binding 3 in place of the spectral table.
|
|
40
|
+
*/
|
|
41
|
+
readonly extraSiteRoundings?: number;
|
|
42
|
+
readonly siteTable?: Float32Array<ArrayBuffer>;
|
|
43
|
+
/**
|
|
44
|
+
* #581: a module whose data is too large for one binding (a large photo) gives group 1 per band instead of `bindings`: for the
|
|
45
|
+
* native site rows [y0, y1] the band reads, and the most display rows a band may hold at `sitesPerDisplayRow`.
|
|
46
|
+
*/
|
|
47
|
+
band?(scope: GpuResourceScope, layout: GPUBindGroupLayout, y0: number, y1: number): GPUBindGroup;
|
|
48
|
+
bandRows?(sitesPerDisplayRow: number): number;
|
|
50
49
|
}
|
|
51
50
|
/** What a GPU render of a display view needs: the reference's own setup and expected-signal input, plus the material module. */
|
|
52
51
|
export interface DisplayViewSpeedGpuInput {
|
|
@@ -77,7 +76,7 @@ export interface DisplayViewSpeedGpuResult extends DisplayViewRenderResult {
|
|
|
77
76
|
/**
|
|
78
77
|
* Why the kernel does not cover a request, or null when it does. The kernel is the Speed path: the exact area mean
|
|
79
78
|
* (views where a footprint holds at most 25 real pixels and at most K², and here at most 6 per axis), no diffraction
|
|
80
|
-
* kernels, chart materials, the bilinear demosaic (no AHD candidates
|
|
79
|
+
* kernels, chart materials, the bilinear demosaic (no AHD candidates), the identity or positive Reinhard
|
|
81
80
|
* tone curve, and at most 16 query offsets.
|
|
82
81
|
*/
|
|
83
82
|
export declare function displayViewSpeedGpuUnsupportedReason(setup: DisplayViewSetup, signalInput: DisplayViewExpectedSignalInput): string | null;
|
|
@@ -101,7 +100,7 @@ export declare function gaussLegendre16(): {
|
|
|
101
100
|
/** One axis record of the geometry buffer: first real pixel, count, overlaps over the scale, axis sums over the squared scale. */
|
|
102
101
|
export declare function axisRecord(geometry: Float32Array, at: number, start: number, end: number, limit: number, margin: number, scale: number): void;
|
|
103
102
|
/** The a-priori relative bounds of the expected value and the variance (docs/WEBGPU.md, "Display view (Speed)"), doubled. */
|
|
104
|
-
export declare function displayViewSpeedGpuRelativeBounds(toneCurve: DisplayViewSetup["toneCurve"]): {
|
|
103
|
+
export declare function displayViewSpeedGpuRelativeBounds(toneCurve: DisplayViewSetup["toneCurve"], extraSiteRoundings?: number): {
|
|
105
104
|
mean: number;
|
|
106
105
|
variance: number;
|
|
107
106
|
};
|
|
@@ -119,6 +118,12 @@ export declare function finishDisplayViewPixel(moments: ArrayLike<number>, pixel
|
|
|
119
118
|
* absolute variance bound; it changes no computed value.
|
|
120
119
|
*/
|
|
121
120
|
export declare function displayViewSpeedQuantizationBound(moments: ArrayLike<number>, relative: number, absolute: number, pixels: number, step: number): number;
|
|
121
|
+
/**
|
|
122
|
+
* Renders the display pixels `indices` (ascending, region row-major) with the reference, a run of consecutive pixels along a row
|
|
123
|
+
* as one region (#457: AHD's choice flags stretches near edges): a region render is byte-identical to the same pixels of the whole
|
|
124
|
+
* view, so each pixel equals its one-pixel render, and a run's counts are the sums of its pixels'.
|
|
125
|
+
*/
|
|
126
|
+
export declare function recomputeRuns(setup: DisplayViewSetup, signalInput: DisplayViewExpectedSignalInput, indices: readonly number[], abort: AbortController, take: (first: number, run: number, part: DisplayViewRenderResult) => void): Promise<void>;
|
|
122
127
|
/** Renders one region of a Speed display view on the GPU (see the module comment). */
|
|
123
128
|
export declare function renderDisplayViewSpeedOnGpu(runtime: WebGpuRuntime, bandBytes: number, input: DisplayViewSpeedGpuInput, abort: AbortController, yieldControl: YieldControl, pipelines: PipelineSource): Promise<DisplayViewSpeedGpuResult>;
|
|
124
129
|
/**
|
|
@@ -130,11 +135,40 @@ export declare function renderDisplayViewSpeedOnGpu(runtime: WebGpuRuntime, band
|
|
|
130
135
|
* render (`displayViewSpeedGpuUnsupportedReason`, `createDisplayViewMaterialModules`).
|
|
131
136
|
*/
|
|
132
137
|
export declare function displayViewSpeedGpuSupports(request: DisplayViewGpuRequest): true | string;
|
|
138
|
+
/** Why the GPU's material lookup, tone curves or query-offset table do not cover a request (shared by the Speed and Quality support checks), or true. */
|
|
139
|
+
export declare function sceneToneAndOffsetsReason(request: DisplayViewGpuRequest, maximumOffsets: number): true | string;
|
|
140
|
+
/**
|
|
141
|
+
* A self-check's verdict: every component of a GPU render inside its a-priori bounds against the reference, every sample within
|
|
142
|
+
* one code, and (#533) the saturated-pixel count the reference's bit for bit; true, or a sentence saying where it failed.
|
|
143
|
+
*/
|
|
144
|
+
export declare function conformanceVerdict(reference: DisplayViewRenderResult, gpu: Pick<DisplayViewSpeedGpuResult, "samples" | "expected" | "noiseStd" | "expectedValueBound" | "varianceBound" | "expectedValueAbsoluteBound" | "varianceAbsoluteBound" | "saturatedPixelCount">): true | string;
|
|
133
145
|
/**
|
|
134
146
|
* The renderer's run-time self-check (`DisplayViewGpuRenderer.conformanceCases`): a 38 × 26 checkerboard frame of 6 µm sites
|
|
135
147
|
* shown at 13 × 9 (2.9 real pixels per display pixel) with the 2 × 2 box, light squares at the white clip, the GPU against
|
|
136
148
|
* `renderDisplayView` within the a-priori bounds, every flagged pixel recomputed.
|
|
137
149
|
*/
|
|
150
|
+
/** The self-checks' common frame: 40 × 28 native sites (a 38 × 26 frame and a one-site margin) shown at 13 × 9, at three spectral nodes. */
|
|
151
|
+
export declare const CONFORMANCE_FRAME: Readonly<{
|
|
152
|
+
nativeWidth: 40;
|
|
153
|
+
nativeHeight: 28;
|
|
154
|
+
margin: 1;
|
|
155
|
+
frameWidth: 38;
|
|
156
|
+
frameHeight: 26;
|
|
157
|
+
nodes: number[];
|
|
158
|
+
}>;
|
|
159
|
+
/** The self-checks' channel responses per node (`scale` 1, or 1/10 for the low-signal correction's few electrons). */
|
|
160
|
+
export declare function conformanceResponses(scale: number): [Float64Array, Float64Array, Float64Array];
|
|
161
|
+
/** The RGGB channel of a native site. */
|
|
162
|
+
export declare const conformanceChannelAt: (x: number, y: number) => number;
|
|
163
|
+
/** The self-checks' checkerboard and its expected-signal scene (neutral materials under a white radiance per node). */
|
|
164
|
+
export declare function conformanceChart(): {
|
|
165
|
+
chart: ReturnType<typeof resolvePortableChartScene>;
|
|
166
|
+
scene: DisplayViewExpectedSignalInput["scene"];
|
|
167
|
+
};
|
|
168
|
+
/** A self-check's setup around its expected-signal input: the common frame and view, the bilinear demosaic, gains, matrix and tone curve, plus `extra`. */
|
|
169
|
+
export declare function conformanceSetup(signalInput: DisplayViewExpectedSignalInput, readout: DisplayViewSetup["readout"][0], seed: number, reachSites: number, signal: AbortSignal | undefined, extra?: Partial<DisplayViewSetup>): DisplayViewSetup;
|
|
170
|
+
/** Runs a self-check's GPU render with an abort controller that follows `signal`, and the device's pipelines under it. */
|
|
171
|
+
export declare function withConformanceAbort<T>(runtime: WebGpuRuntime, signal: AbortSignal | undefined, run: (abort: AbortController, pipelines: PipelineSource) => Promise<T>): Promise<T>;
|
|
138
172
|
export declare const DISPLAY_VIEW_SPEED_CONFORMANCE_CASE: DisplayViewGpuConformanceCase;
|
|
139
173
|
/**
|
|
140
174
|
* The display view's Speed renderer on one runtime (#481's `DisplayViewGpuRenderer`): one pipeline cache per device, the
|
|
@@ -155,4 +189,18 @@ export declare const displayViewSpeedGpuRendererFactory: DisplayViewGpuRendererF
|
|
|
155
189
|
* registered before. Nothing registers it on import: the integration of #481 decides where the engine registers it.
|
|
156
190
|
*/
|
|
157
191
|
export declare function registerDisplayViewSpeedGpuRenderer(): DisplayViewGpuRendererFactory | null;
|
|
192
|
+
/** #564: the GPU refusal of a defocus kernel above the direct radius (the CPU convolves it by runs). */
|
|
193
|
+
export declare const LARGE_DEFOCUS_REASON = "a defocus kernel radius above 64 sites (convolved by runs on the CPU, #564) is not on the GPU";
|
|
194
|
+
/** The footprint shape of a view: real pixels per display pixel along each axis, and whether the exact area mean applies. */
|
|
195
|
+
export declare function footprintShape(setup: DisplayViewSetup): {
|
|
196
|
+
sx: number;
|
|
197
|
+
sy: number;
|
|
198
|
+
exact: boolean;
|
|
199
|
+
maximumColumns: number;
|
|
200
|
+
maximumRows: number;
|
|
201
|
+
};
|
|
202
|
+
/** The pixel-aperture samples per axis and anti-aliasing spots of a request. */
|
|
203
|
+
export declare function offsetCount(request: DisplayViewGpuRequest): number;
|
|
204
|
+
/** The bilinear RGGB demosaic kernels per phase (phaseY·2 + phaseX) and channel, as `bilinearPhaseProfiles` gives them. */
|
|
205
|
+
export declare function bilinearKernels(): DisplayViewKernelTap[][][];
|
|
158
206
|
export {};
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
* #477); `display-view-chart-material-module.ts` provides one for the eight 2.0 chart presets and
|
|
14
14
|
* `display-view-composite-material-module.ts` (#491) one for composite charts, the 2.3 elements and `material-layers` scenes.
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
16
|
+
import { SDR_LUMINANCE_WEIGHTS } from "../output/sdr-rendering.js";
|
|
17
|
+
import { DISPLAY_VIEW_NOISE_STREAM_ID, EXACT_AREA_MEAN_MAX_PIXELS, axisSums, clipCentre, createDisplayViewExpectedSignal, displayViewDecidedSaturation, overlaps, quantizationVariance, renderDisplayView } from "../facade/display-view.js";
|
|
18
|
+
import { displayViewSignalTables } from "../facade/expected-signal.js";
|
|
17
19
|
import { resolvePortableChartScene } from "../facade/chart-scenes.js";
|
|
18
20
|
import { setDisplayViewGpuRendererFactory } from "../facade/display-view-gpu.js";
|
|
19
21
|
import { createDisplayViewMaterialModules } from "./display-view-composite-material-module.js";
|
|
@@ -23,8 +25,7 @@ import { createDeterministicUniformStream, deriveNativeSiteStreamSeedUint32, sam
|
|
|
23
25
|
import { createHostYieldGate } from "../capture/host-yield-cadence.js";
|
|
24
26
|
import { ImageKernelExecutionError, WEBGPU_F32_UNIT_ROUNDOFF, webGpuExecution } from "./image-kernel-execution.js";
|
|
25
27
|
import { BUFFER_USAGE, GpuResourceScope, abortedError, createComputePipeline, linearDispatch, runComputePass, throwIfAborted as checkAbort } from "./webgpu-runtime.js";
|
|
26
|
-
import { DISPLAY_VIEW_AUX, DISPLAY_VIEW_FLAG_WORDS, DISPLAY_VIEW_GEOMETRY_STRIDE, DISPLAY_VIEW_GPU_MAXIMUM_OFFSETS, DISPLAY_VIEW_GPU_MAXIMUM_PIXELS_PER_AXIS, DISPLAY_VIEW_OUTPUT_FLOATS, DISPLAY_VIEW_PARAM_WORDS, DISPLAY_VIEW_REINHARD_MEAN_U, DISPLAY_VIEW_REINHARD_VARIANCE_U, DISPLAY_VIEW_WORKGROUP_SIZE, assembleDisplayViewSpeedWgsl } from "./wgsl-display-view-speed-kernel.js";
|
|
27
|
-
import { footprintShape, bilinearKernels, offsetCount } from "./display-view-quality-gpu.js";
|
|
28
|
+
import { DISPLAY_VIEW_AUX, DISPLAY_VIEW_FLAG_WORDS, DISPLAY_VIEW_SPEED_MAXIMUM_NODES, DISPLAY_VIEW_GEOMETRY_STRIDE, DISPLAY_VIEW_GPU_MAXIMUM_OFFSETS, DISPLAY_VIEW_GPU_MAXIMUM_PIXELS_PER_AXIS, DISPLAY_VIEW_OUTPUT_FLOATS, DISPLAY_VIEW_PARAM_WORDS, DISPLAY_VIEW_REINHARD_MEAN_U, DISPLAY_VIEW_REINHARD_VARIANCE_U, DISPLAY_VIEW_WORKGROUP_SIZE, assembleDisplayViewSpeedWgsl } from "./wgsl-display-view-speed-kernel.js";
|
|
28
29
|
/** One WGSL rounding of + − × in either direction (W3C WGSL "Floating Point Accuracy"; #471, #487): twice the binary32 unit roundoff. */
|
|
29
30
|
const E = 2 * WEBGPU_F32_UNIT_ROUNDOFF;
|
|
30
31
|
/** Higham's γ_k with E in place of u. */
|
|
@@ -52,7 +53,7 @@ const BYTES_PER_PIXEL = 4 * DISPLAY_VIEW_OUTPUT_FLOATS + 4 * DISPLAY_VIEW_FLAG_W
|
|
|
52
53
|
/**
|
|
53
54
|
* Why the kernel does not cover a request, or null when it does. The kernel is the Speed path: the exact area mean
|
|
54
55
|
* (views where a footprint holds at most 25 real pixels and at most K², and here at most 6 per axis), no diffraction
|
|
55
|
-
* kernels, chart materials, the bilinear demosaic (no AHD candidates
|
|
56
|
+
* kernels, chart materials, the bilinear demosaic (no AHD candidates), the identity or positive Reinhard
|
|
56
57
|
* tone curve, and at most 16 query offsets.
|
|
57
58
|
*/
|
|
58
59
|
export function displayViewSpeedGpuUnsupportedReason(setup, signalInput) {
|
|
@@ -60,16 +61,22 @@ export function displayViewSpeedGpuUnsupportedReason(setup, signalInput) {
|
|
|
60
61
|
return "a defocus kernel radius above 64 sites (convolved by runs on the CPU, #564) is not on the GPU";
|
|
61
62
|
if (signalInput.kernels)
|
|
62
63
|
return "diffraction kernels (the Quality path) are not on the GPU";
|
|
63
|
-
if (signalInput.scene.kind !== "materials")
|
|
64
|
+
if (signalInput.scene.kind !== "materials" && !signalInput.scene.signalAt)
|
|
64
65
|
return "radiance scenes (caller functions) are not on the GPU";
|
|
65
66
|
if (!signalInput.queryPoint)
|
|
66
67
|
return "the expected signal has no query points";
|
|
67
|
-
if (setup.candidates || setup.
|
|
68
|
-
return "AHD candidates
|
|
69
|
-
if (
|
|
68
|
+
if (setup.candidates || setup.ahdChoice)
|
|
69
|
+
return "AHD candidates are not on the GPU";
|
|
70
|
+
if (!GPU_TONE_CURVES.includes(setup.toneCurve))
|
|
70
71
|
return "unsupported tone curve " + String(setup.toneCurve);
|
|
72
|
+
if (setup.rendering && !setup.coupled)
|
|
73
|
+
return "the coupled rendering steps were not prepared";
|
|
74
|
+
if (setup.rendering?.highlightMode === "reconstruct-neighbors")
|
|
75
|
+
return "highlightMode reconstruct-neighbors (#602; its regions' ratios are found on the host) is not on the GPU in 2.22.0";
|
|
71
76
|
if (signalInput.offsets.length < 1 || signalInput.offsets.length > DISPLAY_VIEW_GPU_MAXIMUM_OFFSETS)
|
|
72
77
|
return "the kernel holds 1 to " + DISPLAY_VIEW_GPU_MAXIMUM_OFFSETS + " query offsets";
|
|
78
|
+
if (signalInput.wavelengthsNm.length < 1 || signalInput.wavelengthsNm.length > DISPLAY_VIEW_SPEED_MAXIMUM_NODES)
|
|
79
|
+
return "the kernel integrates 1 to " + DISPLAY_VIEW_SPEED_MAXIMUM_NODES + " spectral nodes per site";
|
|
73
80
|
if (setup.region.width < 1 || setup.region.height < 1)
|
|
74
81
|
return "an empty region";
|
|
75
82
|
const shape = footprintShape(setup);
|
|
@@ -85,27 +92,19 @@ export function displayViewSpeedGpuUnsupportedReason(setup, signalInput) {
|
|
|
85
92
|
}
|
|
86
93
|
return null;
|
|
87
94
|
}
|
|
88
|
-
/**
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
for (let n = 0; n < nodes; n++)
|
|
102
|
-
value += A[c][n] * m.radiance[n];
|
|
103
|
-
}
|
|
104
|
-
if (!(Math.abs(value) <= FLOAT32_SAFE_MAGNITUDE))
|
|
105
|
-
throw new ImageKernelExecutionError("unsupported-float32-domain", "A material's channel signal exceeds the float32 domain.");
|
|
106
|
-
table[index * 3 + c] = value;
|
|
107
|
-
}
|
|
108
|
-
});
|
|
95
|
+
/**
|
|
96
|
+
* The spectral table (2.21.0: signals are integrated from the material spectrum per site): the three channel responses A_c(λ_n)
|
|
97
|
+
* (3·N floats), then each material's spectral radiance L_m(λ_n) (N floats per material; a neutral one its reflectance times the
|
|
98
|
+
* white radiance, the reference's own float64 spectra), each rounded once to float32. The kernel integrates Σ_n A_c(λ_n)·L_m(λ_n)
|
|
99
|
+
* for the material and channel a site reads, when it reads it; no per-material channel value is formed.
|
|
100
|
+
*
|
|
101
|
+
* Domain: every value is non-negative and the largest possible sum, N·max A·max L, stays below the float32 safe magnitude (NaN fails it).
|
|
102
|
+
*/
|
|
103
|
+
function spectralTable(signalInput) {
|
|
104
|
+
const N = signalInput.wavelengthsNm.length, rows = [...signalInput.electronsPerRadiance, ...displayViewSignalTables(signalInput).spectra], largest = [0, 0];
|
|
105
|
+
const table = Float32Array.from(rows.flatMap((row, r) => Array.from(row.subarray(0, N), (v) => { largest[r < 3 ? 0 : 1] = Math.max(largest[r < 3 ? 0 : 1], v >= 0 ? v : Infinity); return v; })));
|
|
106
|
+
if (!(largest[0] * largest[1] * N <= FLOAT32_SAFE_MAGNITUDE))
|
|
107
|
+
throw new ImageKernelExecutionError("unsupported-float32-domain", "A material's channel signal exceeds the float32 domain.");
|
|
109
108
|
return table;
|
|
110
109
|
}
|
|
111
110
|
/**
|
|
@@ -173,6 +172,8 @@ export function axisRecord(geometry, at, start, end, limit, margin, scale) {
|
|
|
173
172
|
const order = ["bEven", "bOdd", "ppEven", "ppOdd", "qqEven", "qqOdd", "pqEven", "pqOdd", "ww"];
|
|
174
173
|
order.forEach((key, i) => { geometry[at + 8 + i] = sums[key] / scale2; });
|
|
175
174
|
}
|
|
175
|
+
/** The kernel's tone code: identity 0, positive Reinhard 1, extended Reinhard (luminance) 2, Naka–Rushton (luminance) 3. */
|
|
176
|
+
const TONE_CODE = { "identity": 0, "positive-reinhard-per-channel": 1, "extended-reinhard-luminance": 2, "naka-rushton-luminance": 3 };
|
|
176
177
|
/** The uniform parameters and the aux table of a render. */
|
|
177
178
|
function constants(setup, signalInput) {
|
|
178
179
|
const params = new ArrayBuffer(4 * DISPLAY_VIEW_PARAM_WORDS), words = new Uint32Array(params), floats = new Float32Array(params);
|
|
@@ -183,8 +184,9 @@ function constants(setup, signalInput) {
|
|
|
183
184
|
words[6] = setup.nativeWidth;
|
|
184
185
|
words[7] = setup.nativeHeight;
|
|
185
186
|
words[8] = setup.region.width;
|
|
186
|
-
words[9] = setup.toneCurve
|
|
187
|
+
words[9] = TONE_CODE[setup.toneCurve];
|
|
187
188
|
words[10] = signalInput.offsets.length;
|
|
189
|
+
words[11] = signalInput.wavelengthsNm.length;
|
|
188
190
|
for (let c = 0; c < 3; c++) {
|
|
189
191
|
floats[12 + c] = setup.readout[c].perElectron;
|
|
190
192
|
floats[16 + c] = setup.readout[c].darkElectrons;
|
|
@@ -218,10 +220,10 @@ function constants(setup, signalInput) {
|
|
|
218
220
|
return { params, aux };
|
|
219
221
|
}
|
|
220
222
|
/** The a-priori relative bounds of the expected value and the variance (docs/WEBGPU.md, "Display view (Speed)"), doubled. */
|
|
221
|
-
export function displayViewSpeedGpuRelativeBounds(toneCurve) {
|
|
223
|
+
export function displayViewSpeedGpuRelativeBounds(toneCurve, extraSiteRoundings = 0) {
|
|
222
224
|
const reinhard = toneCurve === "positive-reinhard-per-channel";
|
|
223
|
-
return { mean: MARGIN * (gammaE(MEAN_ROUNDINGS) + CPU_RELATIVE + (reinhard ? DISPLAY_VIEW_REINHARD_MEAN_U * E : 0)),
|
|
224
|
-
variance: MARGIN * (gammaE(VARIANCE_ROUNDINGS) + CPU_RELATIVE + (reinhard ? DISPLAY_VIEW_REINHARD_VARIANCE_U * E : 0)) };
|
|
225
|
+
return { mean: MARGIN * (gammaE(MEAN_ROUNDINGS + extraSiteRoundings) + CPU_RELATIVE + (reinhard ? DISPLAY_VIEW_REINHARD_MEAN_U * E : 0)),
|
|
226
|
+
variance: MARGIN * (gammaE(VARIANCE_ROUNDINGS + 2 * extraSiteRoundings) + CPU_RELATIVE + (reinhard ? DISPLAY_VIEW_REINHARD_VARIANCE_U * E : 0)) };
|
|
225
227
|
}
|
|
226
228
|
/**
|
|
227
229
|
* The reference's finishing of one display pixel from its linear-light moments (display-view.ts, after the sample loop):
|
|
@@ -263,13 +265,31 @@ export function displayViewSpeedQuantizationBound(moments, relative, absolute, p
|
|
|
263
265
|
}
|
|
264
266
|
return MARGIN * pixels * largest * step * step / 12;
|
|
265
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* Renders the display pixels `indices` (ascending, region row-major) with the reference, a run of consecutive pixels along a row
|
|
270
|
+
* as one region (#457: AHD's choice flags stretches near edges): a region render is byte-identical to the same pixels of the whole
|
|
271
|
+
* view, so each pixel equals its one-pixel render, and a run's counts are the sums of its pixels'.
|
|
272
|
+
*/
|
|
273
|
+
export async function recomputeRuns(setup, signalInput, indices, abort, take) {
|
|
274
|
+
const region = setup.region;
|
|
275
|
+
let reference;
|
|
276
|
+
for (let r = 0; r < indices.length;) {
|
|
277
|
+
checkAbort(abort.signal);
|
|
278
|
+
const first = indices[r], rx = first % region.width, ry = (first - rx) / region.width;
|
|
279
|
+
let run = 1;
|
|
280
|
+
while (r + run < indices.length && indices[r + run] === first + run && rx + run < region.width)
|
|
281
|
+
run++;
|
|
282
|
+
take(first, run, await renderDisplayView({ ...setup, signal: reference ??= createDisplayViewExpectedSignal(signalInput), region: { x: region.x + rx, y: region.y + ry, width: run, height: 1 } }));
|
|
283
|
+
r += run;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
266
286
|
/** Renders one region of a Speed display view on the GPU (see the module comment). */
|
|
267
287
|
export async function renderDisplayViewSpeedOnGpu(runtime, bandBytes, input, abort, yieldControl, pipelines) {
|
|
268
288
|
const { setup, signalInput, material } = input;
|
|
269
289
|
const reason = displayViewSpeedGpuUnsupportedReason(setup, signalInput);
|
|
270
290
|
if (reason)
|
|
271
291
|
throw new ImageKernelExecutionError("unsupported-on-backend", "webgpu-f32 display view (Speed): " + reason + "; use cpu-reference.");
|
|
272
|
-
const { region, margin } = setup, shape = footprintShape(setup), table = siteTable(signalInput), { params, aux } = constants(setup, signalInput);
|
|
292
|
+
const { region, margin } = setup, shape = footprintShape(setup), table = material.siteTable ?? spectralTable(signalInput), { params, aux } = constants(setup, signalInput);
|
|
273
293
|
const stride = DISPLAY_VIEW_GEOMETRY_STRIDE, geometry = new Float32Array((region.width + region.height) * stride);
|
|
274
294
|
const columnSums = [], rowSums = [];
|
|
275
295
|
for (let i = 0; i < region.width; i++) {
|
|
@@ -281,19 +301,26 @@ export async function renderDisplayViewSpeedOnGpu(runtime, bandBytes, input, abo
|
|
|
281
301
|
rowSums.push(axisSums((region.y + j) * shape.sy, (region.y + j + 1) * shape.sy, setup.frameHeight, margin));
|
|
282
302
|
}
|
|
283
303
|
const area = shape.sx * shape.sy, pixelCount = region.width * region.height;
|
|
284
|
-
const rows = Math.max(1, Math.min(region.height, Math.floor(bandBytes / (region.width * BYTES_PER_PIXEL))));
|
|
304
|
+
const rows = Math.max(1, Math.min(region.height, Math.floor(bandBytes / (region.width * BYTES_PER_PIXEL)), material.bandRows?.(shape.sy) ?? Infinity));
|
|
285
305
|
if (Math.max(rows * region.width * 4 * DISPLAY_VIEW_OUTPUT_FLOATS, geometry.byteLength, table.byteLength) > runtime.maximumStorageBindingBytes)
|
|
286
306
|
throw new ImageKernelExecutionError("insufficient-limits", "One display-view band exceeds the device's storage binding limit.");
|
|
287
|
-
|
|
307
|
+
// #593, #601: the coupled steps' shader text and constants, loaded on demand for a view that asks for them.
|
|
308
|
+
const coupled = setup.rendering ? await import("./wgsl-display-view-coupled.js") : null;
|
|
309
|
+
const coupledConstants = coupled ? coupled.displayViewCoupledConstants(setup, SDR_LUMINANCE_WEIGHTS, gaussLegendre16()) : new Float32Array(1);
|
|
310
|
+
const pipeline = await pipelines("photivra-display-view-speed:" + material.id + (coupled ? "+coupled" : ""), assembleDisplayViewSpeedWgsl(material.wgsl, coupled?.DISPLAY_VIEW_COUPLED_WGSL));
|
|
288
311
|
const moments = new Float32Array(pixelCount * DISPLAY_VIEW_OUTPUT_FLOATS), flagged = [], flagWords = new Uint32Array(pixelCount * DISPLAY_VIEW_FLAG_WORDS);
|
|
289
312
|
const words = new Uint32Array(params);
|
|
290
313
|
const scope = new GpuResourceScope(runtime);
|
|
291
314
|
try {
|
|
292
|
-
|
|
315
|
+
// #593, #601: the coupled steps' constants follow the aux table's own entries (one zero word without them).
|
|
316
|
+
const auxWithCoupled = new Float32Array(aux.length + coupledConstants.length);
|
|
317
|
+
auxWithCoupled.set(aux);
|
|
318
|
+
auxWithCoupled.set(coupledConstants, aux.length);
|
|
319
|
+
const auxBuffer = scope.upload("photivra-display-view-aux", auxWithCoupled, BUFFER_USAGE.STORAGE);
|
|
293
320
|
const geometryBuffer = scope.upload("photivra-display-view-geometry", geometry, BUFFER_USAGE.STORAGE);
|
|
294
321
|
const tableBuffer = scope.upload("photivra-display-view-table", table, BUFFER_USAGE.STORAGE);
|
|
295
|
-
const
|
|
296
|
-
|
|
322
|
+
const materialGroup = material.band ? null : runtime.device.createBindGroup({ layout: pipeline.getBindGroupLayout(1), entries: material.bindings.map((b) => ({ binding: b.binding,
|
|
323
|
+
resource: { buffer: b.buffer ?? scope.upload("photivra-display-view-material-" + b.binding, b.data, b.kind === "uniform" ? BUFFER_USAGE.UNIFORM : BUFFER_USAGE.STORAGE) } })) });
|
|
297
324
|
const gate = createHostYieldGate();
|
|
298
325
|
for (let row0 = 0; row0 < region.height; row0 += rows) {
|
|
299
326
|
checkAbort(abort.signal);
|
|
@@ -309,7 +336,8 @@ export async function renderDisplayViewSpeedOnGpu(runtime, bandBytes, input, abo
|
|
|
309
336
|
{ binding: 0, resource: { buffer: uniform } }, { binding: 1, resource: { buffer: auxBuffer } }, { binding: 2, resource: { buffer: geometryBuffer } },
|
|
310
337
|
{ binding: 3, resource: { buffer: tableBuffer } }, { binding: 4, resource: { buffer: out } }, { binding: 5, resource: { buffer: flagBuffer } }
|
|
311
338
|
] });
|
|
312
|
-
|
|
339
|
+
// #581: a module that bands its own data (a large photo) gives group 1 per band, for the native rows the band reads (with margin).
|
|
340
|
+
const [data, flagData] = await runComputePass(runtime, band, pipeline, [bindGroup, materialGroup ?? material.band(band, pipeline.getBindGroupLayout(1), Math.floor((region.y + row0) * shape.sy) + margin - 2, Math.ceil((region.y + row1) * shape.sy) + margin + 2)], linearDispatch(count, DISPLAY_VIEW_WORKGROUP_SIZE, runtime.maximumWorkgroupsPerDimension), [{ buffer: out, bytes: count * 4 * DISPLAY_VIEW_OUTPUT_FLOATS }, { buffer: flagBuffer, bytes: count * 4 * DISPLAY_VIEW_FLAG_WORDS }], abort.signal);
|
|
313
341
|
moments.set(new Float32Array(data, 0, count * DISPLAY_VIEW_OUTPUT_FLOATS), first * DISPLAY_VIEW_OUTPUT_FLOATS);
|
|
314
342
|
const bandFlags = new Uint32Array(flagData, 0, count * DISPLAY_VIEW_FLAG_WORDS);
|
|
315
343
|
flagWords.set(bandFlags, first * DISPLAY_VIEW_FLAG_WORDS);
|
|
@@ -341,7 +369,7 @@ export async function renderDisplayViewSpeedOnGpu(runtime, bandBytes, input, abo
|
|
|
341
369
|
const expected = new Float64Array(pixelCount * 3), noiseStd = new Float64Array(pixelCount * 3), saturated = new Float64Array(pixelCount);
|
|
342
370
|
const meanBound = new Float32Array(pixelCount), varianceBound = new Float32Array(pixelCount);
|
|
343
371
|
let largestMean = 0, largestVariance = 0, sampleCount = 0, siteCount = 0;
|
|
344
|
-
const counts = new Int32Array(geometry.buffer), relative = displayViewSpeedGpuRelativeBounds(setup.toneCurve);
|
|
372
|
+
const counts = new Int32Array(geometry.buffer), relative = displayViewSpeedGpuRelativeBounds(setup.toneCurve, material.extraSiteRoundings ?? 0);
|
|
345
373
|
// #533: each display pixel's saturated-pixel share from the kernel's mask (the reference's arithmetic, exact where it decided).
|
|
346
374
|
const columnOverlaps = Array.from({ length: region.width }, (_, i) => overlaps((region.x + i) * shape.sx, (region.x + i + 1) * shape.sx, setup.frameWidth));
|
|
347
375
|
for (let ry = 0, i = 0; ry < region.height; ry++) {
|
|
@@ -372,33 +400,29 @@ export async function renderDisplayViewSpeedOnGpu(runtime, bandBytes, input, abo
|
|
|
372
400
|
for (let i = 0; i < pixelCount; i++)
|
|
373
401
|
if (isFlagged[i] === 0 && (flagWords[DISPLAY_VIEW_FLAG_WORDS * i] & 2) !== 0)
|
|
374
402
|
undecided.push(i);
|
|
375
|
-
if (input.recomputeFlagged !== false
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
const rx = i % region.width, ry = (i - rx) / region.width;
|
|
392
|
-
saturated[i] = (await renderDisplayView({ ...setup, signal, region: { x: region.x + rx, y: region.y + ry, width: 1, height: 1 } })).saturated[0];
|
|
393
|
-
highlights.push(i);
|
|
394
|
-
}
|
|
403
|
+
if (input.recomputeFlagged !== false) {
|
|
404
|
+
await recomputeRuns(setup, signalInput, flagged, abort, (first, run, part) => {
|
|
405
|
+
samples.set(part.samples, first * 3);
|
|
406
|
+
expected.set(part.expected, first * 3);
|
|
407
|
+
noiseStd.set(part.noiseStd, first * 3);
|
|
408
|
+
saturated.set(part.saturated, first);
|
|
409
|
+
for (let k = 0; k < run; k++) {
|
|
410
|
+
meanBound[first + k] = 0;
|
|
411
|
+
varianceBound[first + k] = 0;
|
|
412
|
+
recomputed.push(first + k);
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
await recomputeRuns(setup, signalInput, undecided, abort, (first, run, part) => { for (let k = 0; k < run; k++) {
|
|
416
|
+
saturated[first + k] = part.saturated[k];
|
|
417
|
+
highlights.push(first + k);
|
|
418
|
+
} });
|
|
395
419
|
}
|
|
396
420
|
let saturatedPixelCount = 0;
|
|
397
421
|
for (let i = 0; i < pixelCount; i++)
|
|
398
422
|
saturatedPixelCount += saturated[i];
|
|
399
423
|
const expectedValueBound = { kind: "relative-to-reference", relative: relative.mean, absolute: largestMean };
|
|
400
424
|
const uncertain = flagged.length - recomputed.length + undecided.length - highlights.length;
|
|
401
|
-
return { samples, expected, noiseStd, sampleCount, siteCount, detailPixelCount: pixelCount, uniformPixelCount: 0,
|
|
425
|
+
return { samples, expected, noiseStd, sampleCount, siteCount, detailPixelCount: pixelCount, uniformPixelCount: 0, estimation: "exact-area-mean", saturated, saturatedPixelCount,
|
|
402
426
|
execution: webGpuExecution(expectedValueBound, uncertain), expectedValueBound,
|
|
403
427
|
varianceBound: { kind: "relative-to-reference", relative: relative.variance, absolute: largestVariance },
|
|
404
428
|
expectedValueAbsoluteBound: meanBound, varianceAbsoluteBound: varianceBound,
|
|
@@ -417,12 +441,38 @@ export function displayViewSpeedGpuSupports(request) {
|
|
|
417
441
|
return "AHD (the Quality demosaic) is not on the GPU";
|
|
418
442
|
if (request.diffraction)
|
|
419
443
|
return "diffraction (the Quality optics) is not on the GPU";
|
|
420
|
-
|
|
444
|
+
return sceneToneAndOffsetsReason(request, DISPLAY_VIEW_GPU_MAXIMUM_OFFSETS);
|
|
445
|
+
}
|
|
446
|
+
/** Why the GPU's material lookup, tone curves or query-offset table do not cover a request (shared by the Speed and Quality support checks), or true. */
|
|
447
|
+
export function sceneToneAndOffsetsReason(request, maximumOffsets) {
|
|
448
|
+
if (request.scene !== "chart" && request.scene !== "material-layers" && request.scene !== "image-plane")
|
|
421
449
|
return "the scene is a caller " + request.scene + "; the GPU material lookup covers engine charts and declared material-layers scenes (describe the scene as material-layers)";
|
|
422
|
-
|
|
450
|
+
// #593: the identity, Reinhard and the two luminance tone curves (the luminance curves through the coupled steps).
|
|
451
|
+
if (!GPU_TONE_CURVES.includes(request.toneCurve))
|
|
423
452
|
return "unsupported tone curve " + String(request.toneCurve);
|
|
424
|
-
if (offsetCount(request) >
|
|
425
|
-
return "more than " +
|
|
453
|
+
if (offsetCount(request) > maximumOffsets)
|
|
454
|
+
return "more than " + maximumOffsets + " query offsets per site";
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
/** The tone curves the GPU kernels render (#593 adds the luminance curves). */
|
|
458
|
+
const GPU_TONE_CURVES = ["identity", "positive-reinhard-per-channel", "extended-reinhard-luminance", "naka-rushton-luminance"];
|
|
459
|
+
/**
|
|
460
|
+
* A self-check's verdict: every component of a GPU render inside its a-priori bounds against the reference, every sample within
|
|
461
|
+
* one code, and (#533) the saturated-pixel count the reference's bit for bit; true, or a sentence saying where it failed.
|
|
462
|
+
*/
|
|
463
|
+
export function conformanceVerdict(reference, gpu) {
|
|
464
|
+
for (let i = 0; i < reference.expected.length; i++) {
|
|
465
|
+
const p = Math.floor(i / 3), e0 = reference.expected[i], e1 = gpu.expected[i], v0 = reference.noiseStd[i] * reference.noiseStd[i], v1 = gpu.noiseStd[i] * gpu.noiseStd[i];
|
|
466
|
+
const expectedLimit = gpu.expectedValueBound.relative * Math.abs(e0) + gpu.expectedValueAbsoluteBound[p], varianceLimit = gpu.varianceBound.relative * v0 + gpu.varianceAbsoluteBound[p];
|
|
467
|
+
if (!(Math.abs(e1 - e0) <= expectedLimit))
|
|
468
|
+
return "component " + i + ": expected value " + e1 + " differs from the reference " + e0 + " by more than the a-priori bound " + expectedLimit + ".";
|
|
469
|
+
if (!(Math.abs(v1 - v0) <= varianceLimit))
|
|
470
|
+
return "component " + i + ": variance " + v1 + " differs from the reference " + v0 + " by more than the a-priori bound " + varianceLimit + ".";
|
|
471
|
+
if (Math.abs(gpu.samples[i] - reference.samples[i]) > 1)
|
|
472
|
+
return "component " + i + ": sample " + gpu.samples[i] + " differs from the reference " + reference.samples[i] + " by more than one code.";
|
|
473
|
+
}
|
|
474
|
+
if (gpu.saturatedPixelCount !== reference.saturatedPixelCount)
|
|
475
|
+
return "the saturated-pixel count " + gpu.saturatedPixelCount + " differs from the reference's " + reference.saturatedPixelCount + ".";
|
|
426
476
|
return true;
|
|
427
477
|
}
|
|
428
478
|
/**
|
|
@@ -430,48 +480,52 @@ export function displayViewSpeedGpuSupports(request) {
|
|
|
430
480
|
* shown at 13 × 9 (2.9 real pixels per display pixel) with the 2 × 2 box, light squares at the white clip, the GPU against
|
|
431
481
|
* `renderDisplayView` within the a-priori bounds, every flagged pixel recomputed.
|
|
432
482
|
*/
|
|
483
|
+
/** The self-checks' common frame: 40 × 28 native sites (a 38 × 26 frame and a one-site margin) shown at 13 × 9, at three spectral nodes. */
|
|
484
|
+
export const CONFORMANCE_FRAME = /* @__PURE__ */ Object.freeze({ nativeWidth: 40, nativeHeight: 28, margin: 1, frameWidth: 38, frameHeight: 26, nodes: [450, 550, 650] });
|
|
485
|
+
/** The self-checks' channel responses per node (`scale` 1, or 1/10 for the low-signal correction's few electrons). */
|
|
486
|
+
export function conformanceResponses(scale) {
|
|
487
|
+
return [Float64Array.of(9000, 30000, 4000).map((v) => v * scale), Float64Array.of(6000, 42000, 9000).map((v) => v * scale), Float64Array.of(30000, 9000, 3000).map((v) => v * scale)];
|
|
488
|
+
}
|
|
489
|
+
/** The RGGB channel of a native site. */
|
|
490
|
+
export const conformanceChannelAt = (x, y) => ((y & 1) === 0 ? ((x & 1) === 0 ? 0 : 1) : ((x & 1) === 0 ? 1 : 2));
|
|
491
|
+
/** The self-checks' checkerboard and its expected-signal scene (neutral materials under a white radiance per node). */
|
|
492
|
+
export function conformanceChart() {
|
|
493
|
+
const chart = resolvePortableChartScene({ scene: { preset: "checkerboard", squaresAcross: 6 }, aspect: CONFORMANCE_FRAME.frameHeight / CONFORMANCE_FRAME.frameWidth });
|
|
494
|
+
return { chart, scene: { kind: "materials", materialAt: (u, v) => chart.materialAt(u, v), materials: chart.materials.map((m) => ({ neutral: m.kind === "neutral" ? m.reflectance : 0.5 })),
|
|
495
|
+
whiteRadiance: Float64Array.of(0.5, 0.9, 0.7) } };
|
|
496
|
+
}
|
|
497
|
+
/** A self-check's setup around its expected-signal input: the common frame and view, the bilinear demosaic, gains, matrix and tone curve, plus `extra`. */
|
|
498
|
+
export function conformanceSetup(signalInput, readout, seed, reachSites, signal, extra = {}) {
|
|
499
|
+
const { frameWidth, frameHeight, margin, nativeWidth, nativeHeight } = CONFORMANCE_FRAME;
|
|
500
|
+
return { frameWidth, frameHeight, margin, nativeWidth, nativeHeight, viewWidth: 13, viewHeight: 9, region: { x: 0, y: 0, width: 13, height: 9 },
|
|
501
|
+
samplesPerAxis: 16, reachSites, bitDepth: 8, seed, signal: createDisplayViewExpectedSignal(signalInput), readout: [readout, readout, readout], demosaic: bilinearKernels(),
|
|
502
|
+
gains: [1.1, 1, 1.6], clipLevel: 1, matrix: [[3.08, -1.54, -0.54], [-0.92, 1.88, 0.045], [0.053, -0.2, 1.15]], toneCurve: "identity",
|
|
503
|
+
yieldControl: async () => undefined, checkAbort: () => { if (signal?.aborted)
|
|
504
|
+
throw abortedError(); }, ...extra };
|
|
505
|
+
}
|
|
506
|
+
/** Runs a self-check's GPU render with an abort controller that follows `signal`, and the device's pipelines under it. */
|
|
507
|
+
export async function withConformanceAbort(runtime, signal, run) {
|
|
508
|
+
const abort = new AbortController(), onAbort = () => abort.abort();
|
|
509
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
510
|
+
try {
|
|
511
|
+
if (signal?.aborted)
|
|
512
|
+
abort.abort();
|
|
513
|
+
return await run(abort, (label, code) => createComputePipeline(runtime, label, code, abort.signal));
|
|
514
|
+
}
|
|
515
|
+
finally {
|
|
516
|
+
signal?.removeEventListener("abort", onAbort);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
433
519
|
export const DISPLAY_VIEW_SPEED_CONFORMANCE_CASE = { id: "display-view:speed:checkerboard-13x9", async run(handle, signal) {
|
|
434
520
|
// The handle is the engine's own runtime (the contract keeps WebGPU types out of the published declarations).
|
|
435
|
-
const runtime = handle;
|
|
436
|
-
const nativeWidth = 40, nativeHeight = 28, margin = 1, frameWidth = 38, frameHeight = 26, g = 2 / frameWidth, nodes = [450, 550, 650];
|
|
437
|
-
const chart = resolvePortableChartScene({ scene: { preset: "checkerboard", squaresAcross: 6 }, aspect: frameHeight / frameWidth });
|
|
521
|
+
const runtime = handle, { nativeWidth, nativeHeight, frameWidth, nodes } = CONFORMANCE_FRAME, g = 2 / frameWidth, { chart, scene } = conformanceChart();
|
|
438
522
|
const offsets = [[-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 }));
|
|
439
|
-
const signalInput = { nativeWidth, nativeHeight, outputWidth: frameWidth, wavelengthsNm: nodes,
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
channelAt: (x, y) => ((y & 1) === 0 ? ((x & 1) === 0 ? 0 : 1) : ((x & 1) === 0 ? 1 : 2)),
|
|
443
|
-
queryPoint: (x, y, o, out) => { out[0] = (x + 0.5 + offsets[o].x - nativeWidth / 2) * g; out[1] = -(y + 0.5 + offsets[o].y - nativeHeight / 2) * g; } };
|
|
444
|
-
const readout = { perElectron: 1 / 60000, darkElectrons: 0.07, constantVariance: 1.5e-9 };
|
|
445
|
-
const setup = { frameWidth, frameHeight, margin, nativeWidth, nativeHeight, viewWidth: 13, viewHeight: 9, region: { x: 0, y: 0, width: 13, height: 9 },
|
|
446
|
-
samplesPerAxis: 16, reachSites: 2, bitDepth: 8, seed: 478, signal: createDisplayViewExpectedSignal(signalInput), readout: [readout, readout, readout], demosaic: bilinearKernels(),
|
|
447
|
-
gains: [1.1, 1, 1.6], clipLevel: 1, matrix: [[3.08, -1.54, -0.54], [-0.92, 1.88, 0.045], [0.053, -0.2, 1.15]], toneCurve: "identity",
|
|
448
|
-
yieldControl: async () => undefined, checkAbort: () => { if (signal?.aborted)
|
|
449
|
-
throw abortedError(); } };
|
|
523
|
+
const signalInput = { nativeWidth, nativeHeight, outputWidth: frameWidth, wavelengthsNm: nodes, electronsPerRadiance: conformanceResponses(1), offsets, scene,
|
|
524
|
+
channelAt: conformanceChannelAt, queryPoint: (x, y, o, out) => { out[0] = (x + 0.5 + offsets[o].x - nativeWidth / 2) * g; out[1] = -(y + 0.5 + offsets[o].y - nativeHeight / 2) * g; } };
|
|
525
|
+
const setup = conformanceSetup(signalInput, { perElectron: 1 / 60000, darkElectrons: 0.07, constantVariance: 1.5e-9 }, 478, 2, signal);
|
|
450
526
|
const reference = await renderDisplayView(setup);
|
|
451
|
-
|
|
452
|
-
signal
|
|
453
|
-
try {
|
|
454
|
-
if (signal?.aborted)
|
|
455
|
-
abort.abort();
|
|
456
|
-
const gpu = await renderDisplayViewSpeedOnGpu(runtime, 1 << 20, { setup, signalInput, material: chartPresetMaterialModule(chart) }, abort, undefined, (label, code) => createComputePipeline(runtime, label, code, abort.signal));
|
|
457
|
-
for (let i = 0; i < reference.expected.length; i++) {
|
|
458
|
-
const p = Math.floor(i / 3), e0 = reference.expected[i], e1 = gpu.expected[i], v0 = reference.noiseStd[i] * reference.noiseStd[i], v1 = gpu.noiseStd[i] * gpu.noiseStd[i];
|
|
459
|
-
const expectedLimit = gpu.expectedValueBound.relative * Math.abs(e0) + gpu.expectedValueAbsoluteBound[p], varianceLimit = gpu.varianceBound.relative * v0 + gpu.varianceAbsoluteBound[p];
|
|
460
|
-
if (!(Math.abs(e1 - e0) <= expectedLimit))
|
|
461
|
-
return "component " + i + ": expected value " + e1 + " differs from the reference " + e0 + " by more than the a-priori bound " + expectedLimit + ".";
|
|
462
|
-
if (!(Math.abs(v1 - v0) <= varianceLimit))
|
|
463
|
-
return "component " + i + ": variance " + v1 + " differs from the reference " + v0 + " by more than the a-priori bound " + varianceLimit + ".";
|
|
464
|
-
if (Math.abs(gpu.samples[i] - reference.samples[i]) > 1)
|
|
465
|
-
return "component " + i + ": sample " + gpu.samples[i] + " differs from the reference " + reference.samples[i] + " by more than one code.";
|
|
466
|
-
}
|
|
467
|
-
// #533: the saturated-pixel count is the reference's, bit for bit (the light squares sit at the white clip).
|
|
468
|
-
if (gpu.saturatedPixelCount !== reference.saturatedPixelCount)
|
|
469
|
-
return "the saturated-pixel count " + gpu.saturatedPixelCount + " differs from the reference's " + reference.saturatedPixelCount + ".";
|
|
470
|
-
return true;
|
|
471
|
-
}
|
|
472
|
-
finally {
|
|
473
|
-
signal?.removeEventListener("abort", onAbort);
|
|
474
|
-
}
|
|
527
|
+
// #533: the verdict includes the saturated-pixel count (the light squares sit at the white clip).
|
|
528
|
+
return await withConformanceAbort(runtime, signal, async (abort, pipelines) => conformanceVerdict(reference, await renderDisplayViewSpeedOnGpu(runtime, 1 << 20, { setup, signalInput, material: chartPresetMaterialModule(chart) }, abort, undefined, pipelines)));
|
|
475
529
|
} };
|
|
476
530
|
/**
|
|
477
531
|
* The display view's Speed renderer on one runtime (#481's `DisplayViewGpuRenderer`): one pipeline cache per device, the
|
|
@@ -510,7 +564,7 @@ export function createDisplayViewSpeedGpuRenderer(runtime, options = {}) {
|
|
|
510
564
|
const material = await modules.moduleFor(setup.gpu, abort.signal);
|
|
511
565
|
const result = await renderDisplayViewSpeedOnGpu(runtime, bandBytes, { setup, signalInput: setup.gpu.signalInput, material }, abort, options.yieldControl, source);
|
|
512
566
|
return { samples: result.samples, expected: result.expected, noiseStd: result.noiseStd, sampleCount: result.sampleCount, siteCount: result.siteCount, detailPixelCount: result.detailPixelCount,
|
|
513
|
-
uniformPixelCount: result.uniformPixelCount,
|
|
567
|
+
uniformPixelCount: result.uniformPixelCount, estimation: result.estimation, saturated: result.saturated,
|
|
514
568
|
saturatedPixelCount: result.saturatedPixelCount, errorBound: result.expectedValueBound,
|
|
515
569
|
diagnosticUncertaintySampleCount: result.execution.diagnosticUncertaintySampleCount, ...(material.compositeProbe ? { compositeProbe: material.compositeProbe } : {}) };
|
|
516
570
|
}
|
|
@@ -530,4 +584,26 @@ export const displayViewSpeedGpuRendererFactory = (handle) => createDisplayViewS
|
|
|
530
584
|
export function registerDisplayViewSpeedGpuRenderer() {
|
|
531
585
|
return setDisplayViewGpuRendererFactory(displayViewSpeedGpuRendererFactory);
|
|
532
586
|
}
|
|
587
|
+
// #594: shared with the on-demand Quality host (display-view-quality-gpu.ts), so the Speed path does not import it.
|
|
588
|
+
/** #564: the GPU refusal of a defocus kernel above the direct radius (the CPU convolves it by runs). */
|
|
589
|
+
export const LARGE_DEFOCUS_REASON = "a defocus kernel radius above 64 sites (convolved by runs on the CPU, #564) is not on the GPU";
|
|
590
|
+
/** The footprint shape of a view: real pixels per display pixel along each axis, and whether the exact area mean applies. */
|
|
591
|
+
export function footprintShape(setup) {
|
|
592
|
+
const sx = setup.frameWidth / setup.viewWidth, sy = setup.frameHeight / setup.viewHeight, area = sx * sy;
|
|
593
|
+
const exact = area <= Math.min(EXACT_AREA_MEAN_MAX_PIXELS, setup.samplesPerAxis * setup.samplesPerAxis);
|
|
594
|
+
let maximumColumns = 0, maximumRows = 0;
|
|
595
|
+
for (let i = 0; i < setup.region.width; i++)
|
|
596
|
+
maximumColumns = Math.max(maximumColumns, overlaps((setup.region.x + i) * sx, (setup.region.x + i + 1) * sx, setup.frameWidth).w.length);
|
|
597
|
+
for (let j = 0; j < setup.region.height; j++)
|
|
598
|
+
maximumRows = Math.max(maximumRows, overlaps((setup.region.y + j) * sy, (setup.region.y + j + 1) * sy, setup.frameHeight).w.length);
|
|
599
|
+
return { sx, sy, exact, maximumColumns, maximumRows };
|
|
600
|
+
}
|
|
601
|
+
/** The pixel-aperture samples per axis and anti-aliasing spots of a request. */
|
|
602
|
+
export function offsetCount(request) { return request.boxSamples * request.boxSamples * (request.antiAliasing ? 4 : 1); }
|
|
603
|
+
/** The bilinear RGGB demosaic kernels per phase (phaseY·2 + phaseX) and channel, as `bilinearPhaseProfiles` gives them. */
|
|
604
|
+
export function bilinearKernels() {
|
|
605
|
+
const cross = [[1, 0], [-1, 0], [0, 1], [0, -1]], diagonal = [[1, 1], [1, -1], [-1, 1], [-1, -1]], horizontal = [[1, 0], [-1, 0]], vertical = [[0, 1], [0, -1]];
|
|
606
|
+
const average = (offsets) => offsets.map(([dx, dy]) => ({ dx: dx, dy: dy, weight: 1 / offsets.length })), self = [{ dx: 0, dy: 0, weight: 1 }];
|
|
607
|
+
return [[self, average(cross), average(diagonal)], [average(horizontal), self, average(vertical)], [average(vertical), self, average(horizontal)], [average(diagonal), average(cross), self]];
|
|
608
|
+
}
|
|
533
609
|
//# sourceMappingURL=display-view-speed-gpu.js.map
|