@photivra/engine 2.1.0 → 2.2.1
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 +27 -1
- package/CITATION.cff +1 -1
- package/README.md +6 -6
- package/SECURITY.md +1 -1
- package/dist/capture/export-jpeg.js +7 -1
- package/dist/capture/export-jpeg.js.map +1 -1
- package/dist/capture/native-environment-lean.js +5 -2
- package/dist/capture/native-environment-lean.js.map +1 -1
- package/dist/capture/native-environment-raw.js +2 -2
- package/dist/capture/native-environment-raw.js.map +1 -1
- package/dist/capture/native-raw-development.js +1 -1
- package/dist/capture/native-raw-development.js.map +1 -1
- package/dist/capture/native-raw.d.ts +16 -0
- package/dist/capture/native-raw.js +16 -3
- package/dist/capture/native-raw.js.map +1 -1
- package/dist/capture/packed-sensor-raw.d.ts +7 -0
- package/dist/capture/packed-sensor-raw.js +6 -2
- package/dist/capture/packed-sensor-raw.js.map +1 -1
- package/dist/core/pixel-limits.d.ts +14 -0
- package/dist/core/pixel-limits.js +40 -0
- package/dist/core/pixel-limits.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/chart-radiance-batch.d.ts +7 -0
- package/dist/facade/chart-radiance-batch.js +7 -3
- package/dist/facade/chart-radiance-batch.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +8 -1
- package/dist/facade/simulate-capture.js +69 -18
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/motion/temporal-exposure-sum.d.ts +7 -0
- package/dist/motion/temporal-exposure-sum.js +6 -2
- package/dist/motion/temporal-exposure-sum.js.map +1 -1
- package/dist/optics/irradiance-convolution.d.ts +7 -0
- package/dist/optics/irradiance-convolution.js +6 -2
- package/dist/optics/irradiance-convolution.js.map +1 -1
- package/dist/optics/lens-psf-kernels.d.ts +3 -1
- package/dist/optics/lens-psf-kernels.js +7 -2
- package/dist/optics/lens-psf-kernels.js.map +1 -1
- package/dist/output/native-capture-sdr.d.ts +7 -0
- package/dist/output/native-capture-sdr.js +6 -3
- package/dist/output/native-capture-sdr.js.map +1 -1
- package/dist/output/png-encoder.d.ts +10 -1
- package/dist/output/png-encoder.js +10 -4
- package/dist/output/png-encoder.js.map +1 -1
- package/dist/output/print-jpeg.d.ts +18 -0
- package/dist/output/print-jpeg.js +15 -4
- package/dist/output/print-jpeg.js.map +1 -1
- package/dist/sensor/sampling-aperture.d.ts +15 -0
- package/dist/sensor/sampling-aperture.js +31 -10
- package/dist/sensor/sampling-aperture.js.map +1 -1
- package/docs/API_REFERENCE.md +11 -1
- package/docs/QUICK_START.md +112 -4
- package/docs/USAGE.md +3 -1
- package/docs/api/capture-native-raw.md +11 -2
- package/docs/api/capture-packed-sensor-raw.md +7 -1
- package/docs/api/core-pixel-limits.md +19 -0
- package/docs/api/core-version.md +1 -1
- package/docs/api/exports.json +17 -2
- package/docs/api/facade-chart-radiance-batch.md +8 -2
- package/docs/api/facade-simulate-capture.md +8 -1
- package/docs/api/motion-temporal-exposure-sum.md +7 -1
- package/docs/api/optics-irradiance-convolution.md +7 -1
- package/docs/api/output-native-capture-sdr.md +7 -2
- package/docs/api/output-png-encoder.md +8 -1
- package/docs/api/output-print-jpeg.md +17 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packed-sensor-raw.js","sourceRoot":"","sources":["../../src/capture/packed-sensor-raw.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Packed sensor stage (#277): expected electrons per native site → seeded Poisson photo and dark charge →\n * physical capacity → Gaussian read noise → pre-ADC limit → ADC (INL, round half up, optional digital\n * gain) → RAW code, on typed arrays for one rectangular region of the native raster.\n *\n * This is the float64 CPU reference for the `webgpu-f32` sensor stage. It runs the same equations, the\n * same seeded noise model (`photivra-native-raw-noise` 0.4.0) and the same floating-point operation\n * order as `calculateNativeRawSite` in the per-site producer, so for the same expected electrons and\n * readout regime its codes are bit-identical to the per-site engine (tested). The per-site stream\n * seeds are MurmurHash3_x86_32 of (capture seed, absolute native row-major index, stream ID), so the\n * region and any banding cannot change a code.\n *\n * Optional (2.0): a fixed-pattern noise profile (`SENSOR_FIXED_PATTERN_NOISE_MODEL`; PRNU and DSNU or\n * hot-pixel factors on the Poisson means, row and column offsets added with read noise) and up to 8\n * additional stored-charge components (Poisson or deterministic), in the producer's exact order.\n *\n * Supported domain (frame-wide, fails closed otherwise): one readout regime, one physical charge\n * capacity, one fixed-pattern profile. See docs/WEBGPU.md.\n */\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { requireAllowlistedRecord } from \"../core/record-validation.js\";\nimport { adcTransfer, resolveSensorReadoutRegime, samplePoisson, type ResolvedSensorReadoutRegime,\n type SensorReadoutConversionProfile } from \"../sensor/raw-readout.js\";\nimport { createDeterministicUniformStream, deriveNativeSiteStreamSeedUint32, sampleDeterministicStandardNormal,\n NATIVE_SITE_CHARGE_STREAM_ID, NATIVE_SITE_READ_NOISE_STREAM_ID } from \"../sensor/stochastic-seed.js\";\nimport { evaluateFixedPatternColumnOffset, evaluateFixedPatternRowOffset, evaluateFixedPatternSiteFactors, parseSensorFixedPatternNoiseProfile,\n type SensorFixedPatternNoiseProfile } from \"../sensor/fixed-pattern-noise.js\";\nimport type { SensorAdditionalChargeSamplingModel } from \"../sensor/raw-readout.js\";\nimport { SENSOR_RAW_PRODUCER_NOISE_MODEL } from \"./sensor-raw-producer.js\";\n\nexport const PACKED_SENSOR_RAW_SCHEMA_VERSION = \"0.1.0\" as const;\nexport const PACKED_SENSOR_RAW_LIMITS = Object.freeze({\n maximumRegionSites: 24_000_000,\n maximumNativeSites: 0xffffffff,\n maximumDimension: 65_535,\n maximumAdcBitDepth: 16,\n maximumReadNoiseComponents: 16,\n maximumAdditionalChargeComponents: 8\n});\n\n/**\n * Optional fixed-pattern noise for a packed region. The colour-sampling site of native site (X, Y) is\n * (X + siteOrigin.x, Y + siteOrigin.y); the pattern is seeded from those coordinates, as in\n * `calculateSensorFixedPatternSite`.\n */\nexport interface PackedSensorFixedPatternNoise {\n profile: SensorFixedPatternNoiseProfile;\n /** Must equal `profile.colorSamplingProfileId`. */\n colorSamplingProfileId: string;\n siteOrigin: { x: number; y: number };\n}\n/** One additional stored-charge component, realized after photo and dark charge in declaration order. */\nexport interface PackedSensorAdditionalChargeComponent {\n componentId: string;\n /** `poisson` draws from the charge stream; `deterministic-expected-electron-equivalent` adds the expectation. */\n model: SensorAdditionalChargeSamplingModel;\n /** Expected electrons per region site, row-major. Finite, ≥ 0. */\n expectedElectrons: Float32Array | Float64Array;\n}\n\nexport interface PackedSensorRawInput {\n schemaVersion: typeof PACKED_SENSOR_RAW_SCHEMA_VERSION;\n /** Full native raster. Site seeds use the absolute index `(region.y + row) * nativeWidth + region.x + column`. */\n nativeWidth: number;\n nativeHeight: number;\n /** Region of the native raster to simulate, in native sites. */\n region: { x: number; y: number; width: number; height: number };\n /** The committed capture's noise seed (`capture.noise.seedUint32`). */\n captureSeedUint32: number;\n /** Expected photo-generated electrons per region site (EQE and local exposure applied), row-major. Finite, ≥ 0. */\n photoElectrons: Float32Array | Float64Array;\n /** Expected dark electrons per region site, row-major. Finite, ≥ 0. */\n darkElectrons: Float32Array | Float64Array;\n /** Physical charge storage capacity in electrons, the same at every site. */\n physicalChargeCapacityElectrons: number;\n readoutProfile: SensorReadoutConversionProfile;\n regimeId: string;\n /** Optional (2.0). */\n fixedPatternNoise?: PackedSensorFixedPatternNoise;\n /** Optional (2.0), at most 8. */\n additionalChargeComponents?: readonly PackedSensorAdditionalChargeComponent[];\n}\n\n/** Validated plan. Arrays are borrowed, not copied. */\nexport interface PackedSensorRawPlan {\n nativeWidth: number;\n nativeHeight: number;\n region: Readonly<{ x: number; y: number; width: number; height: number }>;\n siteCount: number;\n captureSeedUint32: number;\n physicalChargeCapacityElectrons: number;\n readout: ResolvedSensorReadoutRegime;\n noiseModel: typeof SENSOR_RAW_PRODUCER_NOISE_MODEL;\n seedSchedule: \"murmur3-capture-seed-native-index-stream-v2\";\n /** Largest expected photo and dark electron counts in the region (before fixed-pattern factors). */\n maximumPhotoElectrons: number;\n maximumDarkElectrons: number;\n /** Parsed fixed-pattern profile and colour-site origin, or null. */\n fixedPatternNoise: Readonly<{ profile: SensorFixedPatternNoiseProfile; siteOrigin: Readonly<{ x: number; y: number }> }> | null;\n /** Additional components (identity, model and largest expectation); their arrays stay on the input. */\n additionalChargeComponents: readonly Readonly<{ componentId: string; model: SensorAdditionalChargeSamplingModel; maximumExpectedElectrons: number }>[];\n}\n\n/** Per-region saturation and clamp counts, as in the per-site readout diagnostics. */\nexport interface PackedSensorRawDiagnostics {\n physicalSaturationSiteCount: number;\n preAdcSaturationSiteCount: number;\n digitalSaturationSiteCount: number;\n lowerClampSiteCount: number;\n}\n\nexport interface PackedSensorRawResult {\n plan: PackedSensorRawPlan;\n /** RAW codes, row-major over the region. */\n codes: Uint16Array;\n diagnostics: PackedSensorRawDiagnostics;\n}\n\nfunction integer(value: unknown, minimum: number, maximum: number): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < minimum || value > maximum) {\n throw new InvalidConfigurationError(\"Invalid packed sensor RAW geometry or seed.\");\n }\n return value;\n}\n\nfunction maximumOf(values: Float32Array | Float64Array, count: number): number {\n if (!(values instanceof Float32Array || values instanceof Float64Array) || values.length !== count) {\n throw new InvalidConfigurationError(\"Packed sensor RAW electron arrays must match the region size.\");\n }\n let maximum = 0;\n for (let i = 0; i < count; i++) {\n const v = values[i]!;\n // The negated comparison also rejects NaN.\n if (!(v >= 0 && v <= Number.MAX_VALUE)) throw new InvalidConfigurationError(\"Expected electrons must be finite and non-negative.\");\n if (v > maximum) maximum = v;\n }\n return maximum;\n}\n\n/** Validates the request (every array value once) and returns its plan. */\nexport function calculatePackedSensorRawPlan(input: PackedSensorRawInput): PackedSensorRawPlan {\n const r = requireAllowlistedRecord(input, [\"schemaVersion\", \"nativeWidth\", \"nativeHeight\", \"region\", \"captureSeedUint32\", \"photoElectrons\",\n \"darkElectrons\", \"physicalChargeCapacityElectrons\", \"readoutProfile\", \"regimeId\", \"fixedPatternNoise\", \"additionalChargeComponents\"],\n \"Invalid packed sensor RAW input.\");\n const L = PACKED_SENSOR_RAW_LIMITS;\n if (r.schemaVersion !== PACKED_SENSOR_RAW_SCHEMA_VERSION) throw new InvalidConfigurationError(\"Unsupported packed sensor RAW schema.\");\n const nativeWidth = integer(r.nativeWidth, 1, L.maximumDimension), nativeHeight = integer(r.nativeHeight, 1, L.maximumDimension);\n if (nativeWidth * nativeHeight > L.maximumNativeSites) throw new InvalidConfigurationError(\"Native raster exceeds the uint32 site index.\");\n const g = requireAllowlistedRecord(r.region, [\"x\", \"y\", \"width\", \"height\"], \"Invalid packed sensor RAW region.\");\n const x = integer(g.x, 0, nativeWidth - 1), y = integer(g.y, 0, nativeHeight - 1);\n const width = integer(g.width, 1, nativeWidth - x), height = integer(g.height, 1, nativeHeight - y);\n if (width * height > L.maximumRegionSites) throw new InvalidConfigurationError(\"Packed sensor RAW region exceeds the site limit.\");\n const captureSeedUint32 = integer(r.captureSeedUint32, 0, 0xffffffff);\n const capacity = r.physicalChargeCapacityElectrons;\n if (typeof capacity !== \"number\" || !(capacity > 0 && capacity <= Number.MAX_VALUE)) {\n throw new InvalidConfigurationError(\"Physical charge capacity must be finite and positive.\");\n }\n const readout = resolveSensorReadoutRegime({ profile: r.readoutProfile as SensorReadoutConversionProfile, regimeId: r.regimeId as string });\n if (readout.regime.adc.bitDepth > L.maximumAdcBitDepth || readout.regime.readNoiseComponents.length > L.maximumReadNoiseComponents) {\n throw new InvalidConfigurationError(\"Packed sensor RAW requires a uint16 ADC and at most 16 read-noise components.\");\n }\n const siteCount = width * height;\n const maximumPhotoElectrons = maximumOf(r.photoElectrons as Float64Array, siteCount);\n const maximumDarkElectrons = maximumOf(r.darkElectrons as Float64Array, siteCount);\n let fixedPatternNoise: PackedSensorRawPlan[\"fixedPatternNoise\"] = null;\n if (r.fixedPatternNoise !== undefined) {\n const f = requireAllowlistedRecord(r.fixedPatternNoise, [\"profile\", \"colorSamplingProfileId\", \"siteOrigin\"], \"Invalid packed fixed-pattern noise.\");\n const profile = parseSensorFixedPatternNoiseProfile(f.profile);\n if (f.colorSamplingProfileId !== profile.colorSamplingProfileId) {\n throw new InvalidConfigurationError(\"Fixed-pattern noise profile colour-sampling identity must match the packed region.\");\n }\n const o = requireAllowlistedRecord(f.siteOrigin, [\"x\", \"y\"], \"Invalid packed fixed-pattern site origin.\");\n const ox = integer(o.x, 0, 0xffffffff - (x + width - 1)), oy = integer(o.y, 0, 0xffffffff - (y + height - 1));\n fixedPatternNoise = Object.freeze({ profile, siteOrigin: Object.freeze({ x: ox, y: oy }) });\n }\n const components = r.additionalChargeComponents === undefined ? [] : r.additionalChargeComponents;\n if (!Array.isArray(components) || components.length > L.maximumAdditionalChargeComponents) {\n throw new InvalidConfigurationError(\"Packed sensor RAW takes at most 8 additional stored-charge components.\");\n }\n const ids = new Set<string>();\n const additionalChargeComponents = components.map((value: unknown) => {\n const c = requireAllowlistedRecord(value, [\"componentId\", \"model\", \"expectedElectrons\"], \"Invalid packed additional charge component.\");\n if (typeof c.componentId !== \"string\" || c.componentId.length === 0 || ids.has(c.componentId) ||\n (c.model !== \"poisson\" && c.model !== \"deterministic-expected-electron-equivalent\")) {\n throw new InvalidConfigurationError(\"Additional charge components need unique IDs and a Poisson or deterministic model.\");\n }\n ids.add(c.componentId);\n return Object.freeze({ componentId: c.componentId, model: c.model as SensorAdditionalChargeSamplingModel,\n maximumExpectedElectrons: maximumOf(c.expectedElectrons as Float64Array, siteCount) });\n });\n return Object.freeze({ nativeWidth, nativeHeight, region: Object.freeze({ x, y, width, height }), siteCount, captureSeedUint32,\n physicalChargeCapacityElectrons: capacity, readout, noiseModel: SENSOR_RAW_PRODUCER_NOISE_MODEL,\n seedSchedule: \"murmur3-capture-seed-native-index-stream-v2\" as const, maximumPhotoElectrons, maximumDarkElectrons,\n fixedPatternNoise, additionalChargeComponents: Object.freeze(additionalChargeComponents) });\n}\n\n/** Fixed-pattern values that one site needs. @internal */\nexport interface PackedSensorSitePattern { photoResponseGainFactor: number; darkCurrentFactor: number; readoutOffsetElectrons: number }\n\n/**\n * Evaluates the fixed-pattern values of region sites with the model's own functions. Row and column\n * offsets are computed once per row and column; `readoutOffsetElectrons` is row + column, as in\n * `calculateSensorFixedPatternSite`. @internal\n */\nexport function createPackedFixedPattern(plan: PackedSensorRawPlan): ((column: number, row: number) => PackedSensorSitePattern) | null {\n const f = plan.fixedPatternNoise;\n if (f === null) return null;\n const { region } = plan, x0 = region.x + f.siteOrigin.x, y0 = region.y + f.siteOrigin.y;\n const rows = new Float64Array(region.height), columns = new Float64Array(region.width);\n for (let row = 0; row < region.height; row++) rows[row] = evaluateFixedPatternRowOffset(f.profile, y0 + row);\n for (let column = 0; column < region.width; column++) columns[column] = evaluateFixedPatternColumnOffset(f.profile, x0 + column);\n return (column, row) => {\n const factors = evaluateFixedPatternSiteFactors(f.profile, x0 + column, y0 + row);\n return { photoResponseGainFactor: factors.photoResponseGainFactor, darkCurrentFactor: factors.darkCurrentFactor,\n readoutOffsetElectrons: rows[row]! + columns[column]! };\n };\n}\n\n/** Saturation and clamp flags of one site: bit 0 physical, 1 pre-ADC, 2 digital, 3 lower clamp. */\nexport const PACKED_SENSOR_RAW_FLAG = Object.freeze({ physical: 1, preAdc: 2, digital: 4, lower: 8 });\n\n/**\n * One site of the reference, in the operation order of `calculateNativeRawSite`. Returns the code and\n * its flags. `index` is the absolute native row-major index; `pattern` is the site's fixed-pattern\n * values (required when the plan has a profile) and `additional` its additional-component expectations,\n * in the plan's order.\n * @internal\n */\nexport function simulatePackedSensorSite(plan: PackedSensorRawPlan, photoE: number, darkE: number, index: number,\n pattern: PackedSensorSitePattern | null = null, additional: readonly number[] = []): { code: number; flags: number } {\n const seed = plan.captureSeedUint32, regime = plan.readout.regime, capacity = plan.physicalChargeCapacityElectrons;\n if ((plan.fixedPatternNoise === null) !== (pattern === null) || additional.length !== plan.additionalChargeComponents.length) {\n throw new InvalidConfigurationError(\"Packed sensor site extras must match the plan.\");\n }\n const random = createDeterministicUniformStream(deriveNativeSiteStreamSeedUint32(seed, index, NATIVE_SITE_CHARGE_STREAM_ID));\n // As in simulateSensorChargeRealization: the fixed-pattern factors multiply the Poisson means.\n const photoMean = pattern === null ? photoE : photoE * pattern.photoResponseGainFactor;\n const darkMean = pattern === null ? darkE : darkE * pattern.darkCurrentFactor;\n const photoRealized = samplePoisson(photoMean, random), darkRealized = samplePoisson(darkMean, random);\n let additionalRealized = 0;\n for (let k = 0; k < additional.length; k++) {\n const expected = additional[k]!;\n additionalRealized = additionalRealized + (plan.additionalChargeComponents[k]!.model === \"poisson\" ? samplePoisson(expected, random) : expected);\n }\n const realized = photoRealized + darkRealized + additionalRealized;\n const readRandom = createDeterministicUniformStream(deriveNativeSiteStreamSeedUint32(seed, index, NATIVE_SITE_READ_NOISE_STREAM_ID));\n const afterPhysical = Math.min(realized, capacity);\n let totalReadNoise = 0;\n for (const component of regime.readNoiseComponents) {\n totalReadNoise = totalReadNoise + (component.rmsElectrons.value === 0 ? 0 : sampleDeterministicStandardNormal(readRandom) * component.rmsElectrons.value);\n }\n const afterReadNoise = afterPhysical + totalReadNoise + (pattern === null ? 0 : pattern.readoutOffsetElectrons);\n const threshold = regime.preAdcSaturationElectronEquivalent.value;\n const afterPreAdc = Math.min(afterReadNoise, threshold);\n const quantized = adcTransfer(regime, plan.readout.adcMaximumCode, afterPreAdc).quantized;\n const saturation = regime.adc.digitalSaturationCode;\n const flags = (afterPhysical < realized ? PACKED_SENSOR_RAW_FLAG.physical : 0) | (afterReadNoise > threshold ? PACKED_SENSOR_RAW_FLAG.preAdc : 0) |\n (quantized >= saturation ? PACKED_SENSOR_RAW_FLAG.digital : 0) | (quantized < 0 ? PACKED_SENSOR_RAW_FLAG.lower : 0);\n return { code: Math.max(0, Math.min(quantized, saturation)), flags };\n}\n\n/**\n * Reference rows `[row0, row1)` of the region into `codes` (indexed from the region start), adding flags\n * into `counts` (physical, pre-ADC, digital, lower).\n * @internal\n */\nexport function simulatePackedSensorRows(plan: PackedSensorRawPlan, photo: Float32Array | Float64Array, dark: Float32Array | Float64Array,\n row0: number, row1: number, codes: Uint16Array, counts: number[], extras: PackedSensorExtras = NO_EXTRAS): void {\n const { region, nativeWidth } = plan;\n const additional = new Array<number>(extras.additional.length).fill(0);\n for (let row = row0; row < row1; row++) {\n for (let column = 0, i = row * region.width; column < region.width; column++, i++) {\n for (let k = 0; k < additional.length; k++) additional[k] = extras.additional[k]![i]!;\n const site = simulatePackedSensorSite(plan, photo[i]!, dark[i]!, (region.y + row) * nativeWidth + region.x + column,\n extras.pattern === null ? null : extras.pattern(column, row), additional);\n codes[i] = site.code;\n if (site.flags & 1) counts[0]!++;\n if (site.flags & 2) counts[1]!++;\n if (site.flags & 4) counts[2]!++;\n if (site.flags & 8) counts[3]!++;\n }\n }\n}\n\n/** Per-site extras of a region: the fixed-pattern evaluator and the additional-component arrays. @internal */\nexport interface PackedSensorExtras {\n pattern: ((column: number, row: number) => PackedSensorSitePattern) | null;\n additional: readonly (Float32Array | Float64Array)[];\n}\nconst NO_EXTRAS: PackedSensorExtras = Object.freeze({ pattern: null, additional: Object.freeze([]) });\n\n/** The extras of a validated input; `snapshot` copies the arrays. @internal */\nexport function packedSensorExtras(plan: PackedSensorRawPlan, input: PackedSensorRawInput, snapshot: boolean): PackedSensorExtras {\n return { pattern: createPackedFixedPattern(plan),\n additional: (input.additionalChargeComponents ?? []).map(c => (snapshot ? c.expectedElectrons.slice() : c.expectedElectrons)) };\n}\n\nexport function packedSensorDiagnostics(counts: readonly number[]): PackedSensorRawDiagnostics {\n return { physicalSaturationSiteCount: counts[0]!, preAdcSaturationSiteCount: counts[1]!, digitalSaturationSiteCount: counts[2]!,\n lowerClampSiteCount: counts[3]! };\n}\n\n/**\n * Synchronous float64 reference for a bounded region. Use the image-kernel accelerator for large\n * regions, host yields or the `webgpu-f32` backend.\n */\nexport function simulatePackedSensorRaw(input: PackedSensorRawInput): PackedSensorRawResult {\n const plan = calculatePackedSensorRawPlan(input);\n const codes = new Uint16Array(plan.siteCount), counts = [0, 0, 0, 0];\n simulatePackedSensorRows(plan, input.photoElectrons, input.darkElectrons, 0, plan.region.height, codes, counts,\n packedSensorExtras(plan, input, false));\n return { plan, codes, diagnostics: packedSensorDiagnostics(counts) };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"packed-sensor-raw.js","sourceRoot":"","sources":["../../src/capture/packed-sensor-raw.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Packed sensor stage (#277): expected electrons per native site → seeded Poisson photo and dark charge →\n * physical capacity → Gaussian read noise → pre-ADC limit → ADC (INL, round half up, optional digital\n * gain) → RAW code, on typed arrays for one rectangular region of the native raster.\n *\n * This is the float64 CPU reference for the `webgpu-f32` sensor stage. It runs the same equations, the\n * same seeded noise model (`photivra-native-raw-noise` 0.4.0) and the same floating-point operation\n * order as `calculateNativeRawSite` in the per-site producer, so for the same expected electrons and\n * readout regime its codes are bit-identical to the per-site engine (tested). The per-site stream\n * seeds are MurmurHash3_x86_32 of (capture seed, absolute native row-major index, stream ID), so the\n * region and any banding cannot change a code.\n *\n * Optional (2.0): a fixed-pattern noise profile (`SENSOR_FIXED_PATTERN_NOISE_MODEL`; PRNU and DSNU or\n * hot-pixel factors on the Poisson means, row and column offsets added with read noise) and up to 8\n * additional stored-charge components (Poisson or deterministic), in the producer's exact order.\n *\n * Supported domain (frame-wide, fails closed otherwise): one readout regime, one physical charge\n * capacity, one fixed-pattern profile. See docs/WEBGPU.md.\n */\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { requireAllowlistedRecord } from \"../core/record-validation.js\";\nimport { FULL_RESOLUTION_CEILING_PIXELS, resolveRaisedLimit } from \"../core/pixel-limits.js\";\nimport { adcTransfer, resolveSensorReadoutRegime, samplePoisson, type ResolvedSensorReadoutRegime,\n type SensorReadoutConversionProfile } from \"../sensor/raw-readout.js\";\nimport { createDeterministicUniformStream, deriveNativeSiteStreamSeedUint32, sampleDeterministicStandardNormal,\n NATIVE_SITE_CHARGE_STREAM_ID, NATIVE_SITE_READ_NOISE_STREAM_ID } from \"../sensor/stochastic-seed.js\";\nimport { evaluateFixedPatternColumnOffset, evaluateFixedPatternRowOffset, evaluateFixedPatternSiteFactors, parseSensorFixedPatternNoiseProfile,\n type SensorFixedPatternNoiseProfile } from \"../sensor/fixed-pattern-noise.js\";\nimport type { SensorAdditionalChargeSamplingModel } from \"../sensor/raw-readout.js\";\nimport { SENSOR_RAW_PRODUCER_NOISE_MODEL } from \"./sensor-raw-producer.js\";\n\nexport const PACKED_SENSOR_RAW_SCHEMA_VERSION = \"0.1.0\" as const;\n/** `maximumRegionSites` is the default region limit; a request may raise it with its own `maximumRegionSites`, up to `ceilingRegionSites`. */\nexport const PACKED_SENSOR_RAW_LIMITS = Object.freeze({\n maximumRegionSites: 24_000_000,\n ceilingRegionSites: FULL_RESOLUTION_CEILING_PIXELS,\n maximumNativeSites: 0xffffffff,\n maximumDimension: 65_535,\n maximumAdcBitDepth: 16,\n maximumReadNoiseComponents: 16,\n maximumAdditionalChargeComponents: 8\n});\n\n/**\n * Optional fixed-pattern noise for a packed region. The colour-sampling site of native site (X, Y) is\n * (X + siteOrigin.x, Y + siteOrigin.y); the pattern is seeded from those coordinates, as in\n * `calculateSensorFixedPatternSite`.\n */\nexport interface PackedSensorFixedPatternNoise {\n profile: SensorFixedPatternNoiseProfile;\n /** Must equal `profile.colorSamplingProfileId`. */\n colorSamplingProfileId: string;\n siteOrigin: { x: number; y: number };\n}\n/** One additional stored-charge component, realized after photo and dark charge in declaration order. */\nexport interface PackedSensorAdditionalChargeComponent {\n componentId: string;\n /** `poisson` draws from the charge stream; `deterministic-expected-electron-equivalent` adds the expectation. */\n model: SensorAdditionalChargeSamplingModel;\n /** Expected electrons per region site, row-major. Finite, ≥ 0. */\n expectedElectrons: Float32Array | Float64Array;\n}\n\nexport interface PackedSensorRawInput {\n schemaVersion: typeof PACKED_SENSOR_RAW_SCHEMA_VERSION;\n /** Full native raster. Site seeds use the absolute index `(region.y + row) * nativeWidth + region.x + column`. */\n nativeWidth: number;\n nativeHeight: number;\n /** Region of the native raster to simulate, in native sites. */\n region: { x: number; y: number; width: number; height: number };\n /** The committed capture's noise seed (`capture.noise.seedUint32`). */\n captureSeedUint32: number;\n /** Expected photo-generated electrons per region site (EQE and local exposure applied), row-major. Finite, ≥ 0. */\n photoElectrons: Float32Array | Float64Array;\n /** Expected dark electrons per region site, row-major. Finite, ≥ 0. */\n darkElectrons: Float32Array | Float64Array;\n /** Physical charge storage capacity in electrons, the same at every site. */\n physicalChargeCapacityElectrons: number;\n readoutProfile: SensorReadoutConversionProfile;\n regimeId: string;\n /** Optional (2.0). */\n fixedPatternNoise?: PackedSensorFixedPatternNoise;\n /** Optional (2.0), at most 8. */\n additionalChargeComponents?: readonly PackedSensorAdditionalChargeComponent[];\n /**\n * Optional opt-in region limit for large sensors: an integer from 1 to `PACKED_SENSOR_RAW_LIMITS.ceilingRegionSites`.\n * Default `PACKED_SENSOR_RAW_LIMITS.maximumRegionSites` (24 000 000). It does not change the result.\n */\n maximumRegionSites?: number;\n}\n\n/** Validated plan. Arrays are borrowed, not copied. */\nexport interface PackedSensorRawPlan {\n nativeWidth: number;\n nativeHeight: number;\n region: Readonly<{ x: number; y: number; width: number; height: number }>;\n siteCount: number;\n captureSeedUint32: number;\n physicalChargeCapacityElectrons: number;\n readout: ResolvedSensorReadoutRegime;\n noiseModel: typeof SENSOR_RAW_PRODUCER_NOISE_MODEL;\n seedSchedule: \"murmur3-capture-seed-native-index-stream-v2\";\n /** Largest expected photo and dark electron counts in the region (before fixed-pattern factors). */\n maximumPhotoElectrons: number;\n maximumDarkElectrons: number;\n /** Parsed fixed-pattern profile and colour-site origin, or null. */\n fixedPatternNoise: Readonly<{ profile: SensorFixedPatternNoiseProfile; siteOrigin: Readonly<{ x: number; y: number }> }> | null;\n /** Additional components (identity, model and largest expectation); their arrays stay on the input. */\n additionalChargeComponents: readonly Readonly<{ componentId: string; model: SensorAdditionalChargeSamplingModel; maximumExpectedElectrons: number }>[];\n}\n\n/** Per-region saturation and clamp counts, as in the per-site readout diagnostics. */\nexport interface PackedSensorRawDiagnostics {\n physicalSaturationSiteCount: number;\n preAdcSaturationSiteCount: number;\n digitalSaturationSiteCount: number;\n lowerClampSiteCount: number;\n}\n\nexport interface PackedSensorRawResult {\n plan: PackedSensorRawPlan;\n /** RAW codes, row-major over the region. */\n codes: Uint16Array;\n diagnostics: PackedSensorRawDiagnostics;\n}\n\nfunction integer(value: unknown, minimum: number, maximum: number): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < minimum || value > maximum) {\n throw new InvalidConfigurationError(\"Invalid packed sensor RAW geometry or seed.\");\n }\n return value;\n}\n\nfunction maximumOf(values: Float32Array | Float64Array, count: number): number {\n if (!(values instanceof Float32Array || values instanceof Float64Array) || values.length !== count) {\n throw new InvalidConfigurationError(\"Packed sensor RAW electron arrays must match the region size.\");\n }\n let maximum = 0;\n for (let i = 0; i < count; i++) {\n const v = values[i]!;\n // The negated comparison also rejects NaN.\n if (!(v >= 0 && v <= Number.MAX_VALUE)) throw new InvalidConfigurationError(\"Expected electrons must be finite and non-negative.\");\n if (v > maximum) maximum = v;\n }\n return maximum;\n}\n\n/** Validates the request (every array value once) and returns its plan. */\nexport function calculatePackedSensorRawPlan(input: PackedSensorRawInput): PackedSensorRawPlan {\n const r = requireAllowlistedRecord(input, [\"schemaVersion\", \"nativeWidth\", \"nativeHeight\", \"region\", \"captureSeedUint32\", \"photoElectrons\",\n \"darkElectrons\", \"physicalChargeCapacityElectrons\", \"readoutProfile\", \"regimeId\", \"fixedPatternNoise\", \"additionalChargeComponents\", \"maximumRegionSites\"],\n \"Invalid packed sensor RAW input.\");\n const L = PACKED_SENSOR_RAW_LIMITS;\n if (r.schemaVersion !== PACKED_SENSOR_RAW_SCHEMA_VERSION) throw new InvalidConfigurationError(\"Unsupported packed sensor RAW schema.\");\n const nativeWidth = integer(r.nativeWidth, 1, L.maximumDimension), nativeHeight = integer(r.nativeHeight, 1, L.maximumDimension);\n if (nativeWidth * nativeHeight > L.maximumNativeSites) throw new InvalidConfigurationError(\"Native raster exceeds the uint32 site index.\");\n const g = requireAllowlistedRecord(r.region, [\"x\", \"y\", \"width\", \"height\"], \"Invalid packed sensor RAW region.\");\n const x = integer(g.x, 0, nativeWidth - 1), y = integer(g.y, 0, nativeHeight - 1);\n const width = integer(g.width, 1, nativeWidth - x), height = integer(g.height, 1, nativeHeight - y);\n const maximumRegionSites = resolveRaisedLimit(r.maximumRegionSites, L.maximumRegionSites, L.ceilingRegionSites,\n \"Packed sensor RAW maximumRegionSites must be an integer from 1 to \" + L.ceilingRegionSites + \".\");\n if (width * height > maximumRegionSites) throw new InvalidConfigurationError(\"Packed sensor RAW region exceeds the site limit.\");\n const captureSeedUint32 = integer(r.captureSeedUint32, 0, 0xffffffff);\n const capacity = r.physicalChargeCapacityElectrons;\n if (typeof capacity !== \"number\" || !(capacity > 0 && capacity <= Number.MAX_VALUE)) {\n throw new InvalidConfigurationError(\"Physical charge capacity must be finite and positive.\");\n }\n const readout = resolveSensorReadoutRegime({ profile: r.readoutProfile as SensorReadoutConversionProfile, regimeId: r.regimeId as string });\n if (readout.regime.adc.bitDepth > L.maximumAdcBitDepth || readout.regime.readNoiseComponents.length > L.maximumReadNoiseComponents) {\n throw new InvalidConfigurationError(\"Packed sensor RAW requires a uint16 ADC and at most 16 read-noise components.\");\n }\n const siteCount = width * height;\n const maximumPhotoElectrons = maximumOf(r.photoElectrons as Float64Array, siteCount);\n const maximumDarkElectrons = maximumOf(r.darkElectrons as Float64Array, siteCount);\n let fixedPatternNoise: PackedSensorRawPlan[\"fixedPatternNoise\"] = null;\n if (r.fixedPatternNoise !== undefined) {\n const f = requireAllowlistedRecord(r.fixedPatternNoise, [\"profile\", \"colorSamplingProfileId\", \"siteOrigin\"], \"Invalid packed fixed-pattern noise.\");\n const profile = parseSensorFixedPatternNoiseProfile(f.profile);\n if (f.colorSamplingProfileId !== profile.colorSamplingProfileId) {\n throw new InvalidConfigurationError(\"Fixed-pattern noise profile colour-sampling identity must match the packed region.\");\n }\n const o = requireAllowlistedRecord(f.siteOrigin, [\"x\", \"y\"], \"Invalid packed fixed-pattern site origin.\");\n const ox = integer(o.x, 0, 0xffffffff - (x + width - 1)), oy = integer(o.y, 0, 0xffffffff - (y + height - 1));\n fixedPatternNoise = Object.freeze({ profile, siteOrigin: Object.freeze({ x: ox, y: oy }) });\n }\n const components = r.additionalChargeComponents === undefined ? [] : r.additionalChargeComponents;\n if (!Array.isArray(components) || components.length > L.maximumAdditionalChargeComponents) {\n throw new InvalidConfigurationError(\"Packed sensor RAW takes at most 8 additional stored-charge components.\");\n }\n const ids = new Set<string>();\n const additionalChargeComponents = components.map((value: unknown) => {\n const c = requireAllowlistedRecord(value, [\"componentId\", \"model\", \"expectedElectrons\"], \"Invalid packed additional charge component.\");\n if (typeof c.componentId !== \"string\" || c.componentId.length === 0 || ids.has(c.componentId) ||\n (c.model !== \"poisson\" && c.model !== \"deterministic-expected-electron-equivalent\")) {\n throw new InvalidConfigurationError(\"Additional charge components need unique IDs and a Poisson or deterministic model.\");\n }\n ids.add(c.componentId);\n return Object.freeze({ componentId: c.componentId, model: c.model as SensorAdditionalChargeSamplingModel,\n maximumExpectedElectrons: maximumOf(c.expectedElectrons as Float64Array, siteCount) });\n });\n return Object.freeze({ nativeWidth, nativeHeight, region: Object.freeze({ x, y, width, height }), siteCount, captureSeedUint32,\n physicalChargeCapacityElectrons: capacity, readout, noiseModel: SENSOR_RAW_PRODUCER_NOISE_MODEL,\n seedSchedule: \"murmur3-capture-seed-native-index-stream-v2\" as const, maximumPhotoElectrons, maximumDarkElectrons,\n fixedPatternNoise, additionalChargeComponents: Object.freeze(additionalChargeComponents) });\n}\n\n/** Fixed-pattern values that one site needs. @internal */\nexport interface PackedSensorSitePattern { photoResponseGainFactor: number; darkCurrentFactor: number; readoutOffsetElectrons: number }\n\n/**\n * Evaluates the fixed-pattern values of region sites with the model's own functions. Row and column\n * offsets are computed once per row and column; `readoutOffsetElectrons` is row + column, as in\n * `calculateSensorFixedPatternSite`. @internal\n */\nexport function createPackedFixedPattern(plan: PackedSensorRawPlan): ((column: number, row: number) => PackedSensorSitePattern) | null {\n const f = plan.fixedPatternNoise;\n if (f === null) return null;\n const { region } = plan, x0 = region.x + f.siteOrigin.x, y0 = region.y + f.siteOrigin.y;\n const rows = new Float64Array(region.height), columns = new Float64Array(region.width);\n for (let row = 0; row < region.height; row++) rows[row] = evaluateFixedPatternRowOffset(f.profile, y0 + row);\n for (let column = 0; column < region.width; column++) columns[column] = evaluateFixedPatternColumnOffset(f.profile, x0 + column);\n return (column, row) => {\n const factors = evaluateFixedPatternSiteFactors(f.profile, x0 + column, y0 + row);\n return { photoResponseGainFactor: factors.photoResponseGainFactor, darkCurrentFactor: factors.darkCurrentFactor,\n readoutOffsetElectrons: rows[row]! + columns[column]! };\n };\n}\n\n/** Saturation and clamp flags of one site: bit 0 physical, 1 pre-ADC, 2 digital, 3 lower clamp. */\nexport const PACKED_SENSOR_RAW_FLAG = Object.freeze({ physical: 1, preAdc: 2, digital: 4, lower: 8 });\n\n/**\n * One site of the reference, in the operation order of `calculateNativeRawSite`. Returns the code and\n * its flags. `index` is the absolute native row-major index; `pattern` is the site's fixed-pattern\n * values (required when the plan has a profile) and `additional` its additional-component expectations,\n * in the plan's order.\n * @internal\n */\nexport function simulatePackedSensorSite(plan: PackedSensorRawPlan, photoE: number, darkE: number, index: number,\n pattern: PackedSensorSitePattern | null = null, additional: readonly number[] = []): { code: number; flags: number } {\n const seed = plan.captureSeedUint32, regime = plan.readout.regime, capacity = plan.physicalChargeCapacityElectrons;\n if ((plan.fixedPatternNoise === null) !== (pattern === null) || additional.length !== plan.additionalChargeComponents.length) {\n throw new InvalidConfigurationError(\"Packed sensor site extras must match the plan.\");\n }\n const random = createDeterministicUniformStream(deriveNativeSiteStreamSeedUint32(seed, index, NATIVE_SITE_CHARGE_STREAM_ID));\n // As in simulateSensorChargeRealization: the fixed-pattern factors multiply the Poisson means.\n const photoMean = pattern === null ? photoE : photoE * pattern.photoResponseGainFactor;\n const darkMean = pattern === null ? darkE : darkE * pattern.darkCurrentFactor;\n const photoRealized = samplePoisson(photoMean, random), darkRealized = samplePoisson(darkMean, random);\n let additionalRealized = 0;\n for (let k = 0; k < additional.length; k++) {\n const expected = additional[k]!;\n additionalRealized = additionalRealized + (plan.additionalChargeComponents[k]!.model === \"poisson\" ? samplePoisson(expected, random) : expected);\n }\n const realized = photoRealized + darkRealized + additionalRealized;\n const readRandom = createDeterministicUniformStream(deriveNativeSiteStreamSeedUint32(seed, index, NATIVE_SITE_READ_NOISE_STREAM_ID));\n const afterPhysical = Math.min(realized, capacity);\n let totalReadNoise = 0;\n for (const component of regime.readNoiseComponents) {\n totalReadNoise = totalReadNoise + (component.rmsElectrons.value === 0 ? 0 : sampleDeterministicStandardNormal(readRandom) * component.rmsElectrons.value);\n }\n const afterReadNoise = afterPhysical + totalReadNoise + (pattern === null ? 0 : pattern.readoutOffsetElectrons);\n const threshold = regime.preAdcSaturationElectronEquivalent.value;\n const afterPreAdc = Math.min(afterReadNoise, threshold);\n const quantized = adcTransfer(regime, plan.readout.adcMaximumCode, afterPreAdc).quantized;\n const saturation = regime.adc.digitalSaturationCode;\n const flags = (afterPhysical < realized ? PACKED_SENSOR_RAW_FLAG.physical : 0) | (afterReadNoise > threshold ? PACKED_SENSOR_RAW_FLAG.preAdc : 0) |\n (quantized >= saturation ? PACKED_SENSOR_RAW_FLAG.digital : 0) | (quantized < 0 ? PACKED_SENSOR_RAW_FLAG.lower : 0);\n return { code: Math.max(0, Math.min(quantized, saturation)), flags };\n}\n\n/**\n * Reference rows `[row0, row1)` of the region into `codes` (indexed from the region start), adding flags\n * into `counts` (physical, pre-ADC, digital, lower).\n * @internal\n */\nexport function simulatePackedSensorRows(plan: PackedSensorRawPlan, photo: Float32Array | Float64Array, dark: Float32Array | Float64Array,\n row0: number, row1: number, codes: Uint16Array, counts: number[], extras: PackedSensorExtras = NO_EXTRAS): void {\n const { region, nativeWidth } = plan;\n const additional = new Array<number>(extras.additional.length).fill(0);\n for (let row = row0; row < row1; row++) {\n for (let column = 0, i = row * region.width; column < region.width; column++, i++) {\n for (let k = 0; k < additional.length; k++) additional[k] = extras.additional[k]![i]!;\n const site = simulatePackedSensorSite(plan, photo[i]!, dark[i]!, (region.y + row) * nativeWidth + region.x + column,\n extras.pattern === null ? null : extras.pattern(column, row), additional);\n codes[i] = site.code;\n if (site.flags & 1) counts[0]!++;\n if (site.flags & 2) counts[1]!++;\n if (site.flags & 4) counts[2]!++;\n if (site.flags & 8) counts[3]!++;\n }\n }\n}\n\n/** Per-site extras of a region: the fixed-pattern evaluator and the additional-component arrays. @internal */\nexport interface PackedSensorExtras {\n pattern: ((column: number, row: number) => PackedSensorSitePattern) | null;\n additional: readonly (Float32Array | Float64Array)[];\n}\nconst NO_EXTRAS: PackedSensorExtras = Object.freeze({ pattern: null, additional: Object.freeze([]) });\n\n/** The extras of a validated input; `snapshot` copies the arrays. @internal */\nexport function packedSensorExtras(plan: PackedSensorRawPlan, input: PackedSensorRawInput, snapshot: boolean): PackedSensorExtras {\n return { pattern: createPackedFixedPattern(plan),\n additional: (input.additionalChargeComponents ?? []).map(c => (snapshot ? c.expectedElectrons.slice() : c.expectedElectrons)) };\n}\n\nexport function packedSensorDiagnostics(counts: readonly number[]): PackedSensorRawDiagnostics {\n return { physicalSaturationSiteCount: counts[0]!, preAdcSaturationSiteCount: counts[1]!, digitalSaturationSiteCount: counts[2]!,\n lowerClampSiteCount: counts[3]! };\n}\n\n/**\n * Synchronous float64 reference for a bounded region. Use the image-kernel accelerator for large\n * regions, host yields or the `webgpu-f32` backend.\n */\nexport function simulatePackedSensorRaw(input: PackedSensorRawInput): PackedSensorRawResult {\n const plan = calculatePackedSensorRawPlan(input);\n const codes = new Uint16Array(plan.siteCount), counts = [0, 0, 0, 0];\n simulatePackedSensorRows(plan, input.photoElectrons, input.darkElectrons, 0, plan.region.height, codes, counts,\n packedSensorExtras(plan, input, false));\n return { plan, codes, diagnostics: packedSensorDiagnostics(counts) };\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Default pixel limit of the full-resolution stages. */
|
|
2
|
+
export declare const FULL_RESOLUTION_DEFAULT_PIXELS = 24000000;
|
|
3
|
+
/** Hard ceiling of an opt-in raised pixel limit: 2^27 = 134 217 728 pixels (16 384 × 8 192). */
|
|
4
|
+
export declare const FULL_RESOLUTION_CEILING_PIXELS = 134217728;
|
|
5
|
+
/**
|
|
6
|
+
* Resolves an optional raised limit: `undefined` gives `defaultValue`; otherwise a safe integer from 1 to
|
|
7
|
+
* `ceiling`. Anything else (non-number, NaN, fraction, zero, negative, above the ceiling) throws `message`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveRaisedLimit(value: unknown, defaultValue: number, ceiling: number, message: string): number;
|
|
10
|
+
/**
|
|
11
|
+
* A budget ceiling sized for the default 24 000 000-pixel limit (a whole number of millions), scaled in
|
|
12
|
+
* proportion to a raised pixel limit and never below its default. Exact integer arithmetic.
|
|
13
|
+
*/
|
|
14
|
+
export declare function scaleBudgetCeiling(defaultCeiling: number, maximumPixels: number): number;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Opt-in raised size limits for the full-resolution stages.
|
|
4
|
+
*
|
|
5
|
+
* Every full-resolution stage admits at most 24 000 000 pixels (about a 24 MP sensor) by default. A caller
|
|
6
|
+
* that has decided it can afford more memory and time may raise a stage's limit with an optional input of
|
|
7
|
+
* the same name as the limit (`maximumPixels`, `maximumRegionSites`, `maximumQueries`), up to that stage's
|
|
8
|
+
* `ceiling*` value. Leaving the input out keeps the default, so default requests, plans and outputs are
|
|
9
|
+
* unchanged. Byte-budget checks (`maximumOutputBytes` and similar) still apply to every request.
|
|
10
|
+
*
|
|
11
|
+
* The ceiling is 2^27 = 134 217 728 pixels (16 384 × 8 192). It covers 100 MP rasters such as
|
|
12
|
+
* 12 252 × 8 168 or 11 552 × 8 664 plus their demosaic margin with about 34 % headroom. It also keeps the
|
|
13
|
+
* largest per-pixel typed array of the pipeline, interleaved float64 RGB (24 bytes per pixel), at 3 GiB,
|
|
14
|
+
* below the 4 GiB ArrayBuffer and 2^32-element typed-array bounds found in current JavaScript engines.
|
|
15
|
+
* Measured memory and time per megapixel are in docs/QUICK_START.md ("Large images").
|
|
16
|
+
*/
|
|
17
|
+
import { InvalidConfigurationError } from "./configuration-error.js";
|
|
18
|
+
/** Default pixel limit of the full-resolution stages. */
|
|
19
|
+
export const FULL_RESOLUTION_DEFAULT_PIXELS = 24_000_000;
|
|
20
|
+
/** Hard ceiling of an opt-in raised pixel limit: 2^27 = 134 217 728 pixels (16 384 × 8 192). */
|
|
21
|
+
export const FULL_RESOLUTION_CEILING_PIXELS = 134_217_728;
|
|
22
|
+
/**
|
|
23
|
+
* Resolves an optional raised limit: `undefined` gives `defaultValue`; otherwise a safe integer from 1 to
|
|
24
|
+
* `ceiling`. Anything else (non-number, NaN, fraction, zero, negative, above the ceiling) throws `message`.
|
|
25
|
+
*/
|
|
26
|
+
export function resolveRaisedLimit(value, defaultValue, ceiling, message) {
|
|
27
|
+
if (value === undefined)
|
|
28
|
+
return defaultValue;
|
|
29
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1 || value > ceiling)
|
|
30
|
+
throw new InvalidConfigurationError(message);
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A budget ceiling sized for the default 24 000 000-pixel limit (a whole number of millions), scaled in
|
|
35
|
+
* proportion to a raised pixel limit and never below its default. Exact integer arithmetic.
|
|
36
|
+
*/
|
|
37
|
+
export function scaleBudgetCeiling(defaultCeiling, maximumPixels) {
|
|
38
|
+
return Math.max(defaultCeiling, Math.floor(defaultCeiling / 1_000_000 * maximumPixels / 24));
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=pixel-limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pixel-limits.js","sourceRoot":"","sources":["../../src/core/pixel-limits.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAErE,yDAAyD;AACzD,MAAM,CAAC,MAAM,8BAA8B,GAAG,UAAU,CAAC;AACzD,gGAAgG;AAChG,MAAM,CAAC,MAAM,8BAA8B,GAAG,WAAW,CAAC;AAE1D;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAc,EAAE,YAAoB,EAAE,OAAe,EAAE,OAAe;IACvG,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,YAAY,CAAC;IAC7C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,OAAO;QAAE,MAAM,IAAI,yBAAyB,CAAC,OAAO,CAAC,CAAC;IAC5I,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,cAAsB,EAAE,aAAqB;IAC9E,OAAO,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,SAAS,GAAG,aAAa,GAAG,EAAE,CAAC,CAAC,CAAC;AAC/F,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Opt-in raised size limits for the full-resolution stages.\n *\n * Every full-resolution stage admits at most 24 000 000 pixels (about a 24 MP sensor) by default. A caller\n * that has decided it can afford more memory and time may raise a stage's limit with an optional input of\n * the same name as the limit (`maximumPixels`, `maximumRegionSites`, `maximumQueries`), up to that stage's\n * `ceiling*` value. Leaving the input out keeps the default, so default requests, plans and outputs are\n * unchanged. Byte-budget checks (`maximumOutputBytes` and similar) still apply to every request.\n *\n * The ceiling is 2^27 = 134 217 728 pixels (16 384 × 8 192). It covers 100 MP rasters such as\n * 12 252 × 8 168 or 11 552 × 8 664 plus their demosaic margin with about 34 % headroom. It also keeps the\n * largest per-pixel typed array of the pipeline, interleaved float64 RGB (24 bytes per pixel), at 3 GiB,\n * below the 4 GiB ArrayBuffer and 2^32-element typed-array bounds found in current JavaScript engines.\n * Measured memory and time per megapixel are in docs/QUICK_START.md (\"Large images\").\n */\nimport { InvalidConfigurationError } from \"./configuration-error.js\";\n\n/** Default pixel limit of the full-resolution stages. */\nexport const FULL_RESOLUTION_DEFAULT_PIXELS = 24_000_000;\n/** Hard ceiling of an opt-in raised pixel limit: 2^27 = 134 217 728 pixels (16 384 × 8 192). */\nexport const FULL_RESOLUTION_CEILING_PIXELS = 134_217_728;\n\n/**\n * Resolves an optional raised limit: `undefined` gives `defaultValue`; otherwise a safe integer from 1 to\n * `ceiling`. Anything else (non-number, NaN, fraction, zero, negative, above the ceiling) throws `message`.\n */\nexport function resolveRaisedLimit(value: unknown, defaultValue: number, ceiling: number, message: string): number {\n if (value === undefined) return defaultValue;\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 1 || value > ceiling) throw new InvalidConfigurationError(message);\n return value;\n}\n\n/**\n * A budget ceiling sized for the default 24 000 000-pixel limit (a whole number of millions), scaled in\n * proportion to a raised pixel limit and never below its default. Exact integer arithmetic.\n */\nexport function scaleBudgetCeiling(defaultCeiling: number, maximumPixels: number): number {\n return Math.max(defaultCeiling, Math.floor(defaultCeiling / 1_000_000 * maximumPixels / 24));\n}\n"]}
|
package/dist/core/version.d.ts
CHANGED
package/dist/core/version.js
CHANGED
package/dist/core/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/core/version.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAgB,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Version of the engine release. Since 1.0.1 it equals the npm package version.\n *\n * New captures and plans record this version as their creator. Archived records keep the\n * version they were made with. Proof-of-concept (POC), schema and model contracts have their\n * own versions. Release checks confirm it matches package.json and the packed package.\n * @see docs/RELEASE_1_0_1.md\n */\nexport const ENGINE_API_VERSION = \"2.1
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/core/version.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAgB,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Version of the engine release. Since 1.0.1 it equals the npm package version.\n *\n * New captures and plans record this version as their creator. Archived records keep the\n * version they were made with. Proof-of-concept (POC), schema and model contracts have their\n * own versions. Release checks confirm it matches package.json and the packed package.\n * @see docs/RELEASE_1_0_1.md\n */\nexport const ENGINE_API_VERSION = \"2.2.1\" as const;\n"]}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { type ChartScene, type ResolvedChartScene } from "./chart-scenes.js";
|
|
2
2
|
import { type CaptureIlluminant, type ResolvedCaptureIlluminant } from "./scene-radiance.js";
|
|
3
3
|
export declare const CHART_RADIANCE_BATCH_SCHEMA_VERSION: "0.1.0";
|
|
4
|
+
/** `maximumQueries` is the default batch limit; a request may raise it with its own `maximumQueries`, up to `ceilingQueries`. */
|
|
4
5
|
export declare const CHART_RADIANCE_BATCH_LIMITS: Readonly<{
|
|
5
6
|
maximumQueries: 24000000;
|
|
7
|
+
ceilingQueries: 134217728;
|
|
6
8
|
maximumWavelengths: 256;
|
|
7
9
|
maximumChannels: 4;
|
|
8
10
|
}>;
|
|
@@ -22,6 +24,11 @@ export interface ChartRadianceBatchInput {
|
|
|
22
24
|
wavelengthIndices?: Uint8Array | Uint16Array;
|
|
23
25
|
/** Spectral integration: per channel (1–4), one finite weight per wavelength. */
|
|
24
26
|
channelWeights?: readonly (readonly number[])[];
|
|
27
|
+
/**
|
|
28
|
+
* Optional opt-in batch limit: an integer from 1 to `CHART_RADIANCE_BATCH_LIMITS.ceilingQueries`. Default
|
|
29
|
+
* `CHART_RADIANCE_BATCH_LIMITS.maximumQueries` (24 000 000). It does not change the values.
|
|
30
|
+
*/
|
|
31
|
+
maximumQueries?: number;
|
|
25
32
|
}
|
|
26
33
|
/** Validated plan with the resolved chart, illuminant and irradiance scale. Arrays are borrowed. */
|
|
27
34
|
export interface ChartRadianceBatchPlan {
|
|
@@ -17,13 +17,16 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
19
19
|
import { requireAllowlistedRecord } from "../core/record-validation.js";
|
|
20
|
+
import { FULL_RESOLUTION_CEILING_PIXELS, resolveRaisedLimit } from "../core/pixel-limits.js";
|
|
20
21
|
import { resolveChartScene } from "./chart-scenes.js";
|
|
21
22
|
import { buildPlanarSceneRadianceProvider, calculateIlluminantIrradianceScale, resolveCaptureIlluminant } from "./scene-radiance.js";
|
|
22
23
|
export const CHART_RADIANCE_BATCH_SCHEMA_VERSION = "0.1.0";
|
|
23
|
-
|
|
24
|
+
/** `maximumQueries` is the default batch limit; a request may raise it with its own `maximumQueries`, up to `ceilingQueries`. */
|
|
25
|
+
export const CHART_RADIANCE_BATCH_LIMITS = Object.freeze({ maximumQueries: 24_000_000, ceilingQueries: FULL_RESOLUTION_CEILING_PIXELS, maximumWavelengths: 256,
|
|
26
|
+
maximumChannels: 4 });
|
|
24
27
|
export function calculateChartRadianceBatchPlan(input) {
|
|
25
28
|
const r = requireAllowlistedRecord(input, ["schemaVersion", "scene", "illuminant", "illuminanceLux", "aspect", "points", "wavelengthsNanometers",
|
|
26
|
-
"wavelengthIndices", "channelWeights"], "Invalid chart radiance batch input.");
|
|
29
|
+
"wavelengthIndices", "channelWeights", "maximumQueries"], "Invalid chart radiance batch input.");
|
|
27
30
|
if (r.schemaVersion !== CHART_RADIANCE_BATCH_SCHEMA_VERSION)
|
|
28
31
|
throw new InvalidConfigurationError("Unsupported chart radiance batch schema.");
|
|
29
32
|
if (typeof r.aspect !== "number" || !(r.aspect > 0 && r.aspect <= Number.MAX_VALUE))
|
|
@@ -32,7 +35,8 @@ export function calculateChartRadianceBatchPlan(input) {
|
|
|
32
35
|
const illuminant = resolveCaptureIlluminant(r.illuminant);
|
|
33
36
|
const irradianceScale = calculateIlluminantIrradianceScale(illuminant.shape, r.illuminanceLux);
|
|
34
37
|
const L = CHART_RADIANCE_BATCH_LIMITS, points = r.points;
|
|
35
|
-
|
|
38
|
+
const maximumQueries = resolveRaisedLimit(r.maximumQueries, L.maximumQueries, L.ceilingQueries, "Chart radiance batch maximumQueries must be an integer from 1 to " + L.ceilingQueries + ".");
|
|
39
|
+
if (!(points instanceof Float32Array || points instanceof Float64Array) || points.length % 2 !== 0 || points.length / 2 > maximumQueries) {
|
|
36
40
|
throw new InvalidConfigurationError("points must be an interleaved Float32Array or Float64Array of (u, v) pairs.");
|
|
37
41
|
}
|
|
38
42
|
for (let i = 0; i < points.length; i++)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-radiance-batch.js","sourceRoot":"","sources":["../../src/facade/chart-radiance-batch.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Batched radiance queries for the engine's procedural chart scenes (#277): many frame points in one\n * call, each answered with spectral radiance at a declared wavelength, or with the spectral integral of\n * that radiance against declared channel weights. This is the float64 CPU reference for the\n * `webgpu-f32` chart-radiance stage (`ImageKernelAccelerator.evaluateChartRadiance`).\n *\n * Every value comes from the chart provider's own `radianceAt` (createPlanarSceneRadianceProvider): a\n * Lambertian reflectance ρ(λ) under the scaled illuminant, L = ρ·k·S(λ)/π. The spectral integral of a\n * query is Σ_j w_cj·L(u, v, λ_j), summed in wavelength order. Charts are uniform-illuminant Lambertian\n * patterns, so a query's integral depends only on its material: the GPU stage uses exactly that.\n *\n * The query shape mirrors a batched provider (one call, queries in, results in the same order). Points\n * are frame units (u right, v up; see chart-scenes.ts); `mapEnvironmentDirectionsToChartPoints` converts\n * environment-direction queries exactly as `evaluateRadiance` does.\n * @see docs/WEBGPU.md, \"Scene radiance on the GPU\".\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { requireAllowlistedRecord } from \"../core/record-validation.js\";\nimport { resolveChartScene, type ChartScene, type ResolvedChartScene } from \"./chart-scenes.js\";\nimport { buildPlanarSceneRadianceProvider, calculateIlluminantIrradianceScale, resolveCaptureIlluminant, type CaptureIlluminant,\n type ResolvedCaptureIlluminant } from \"./scene-radiance.js\";\n\nexport const CHART_RADIANCE_BATCH_SCHEMA_VERSION = \"0.1.0\" as const;\nexport const CHART_RADIANCE_BATCH_LIMITS = Object.freeze({ maximumQueries: 24_000_000, maximumWavelengths: 256, maximumChannels: 4 });\n\nexport interface ChartRadianceBatchInput {\n schemaVersion: typeof CHART_RADIANCE_BATCH_SCHEMA_VERSION;\n /** An engine chart preset (caller scene functions are not supported here). */\n scene: ChartScene;\n illuminant: CaptureIlluminant;\n illuminanceLux: number;\n /** Frame height / width. */\n aspect: number;\n /** Frame points, interleaved [u0, v0, u1, v1, …]. Finite. */\n points: Float32Array | Float64Array;\n /** The wavelengths the queries use, in nanometres (1–256). */\n wavelengthsNanometers: readonly number[];\n /** Radiance queries: one wavelength index per point. Exactly one of this and `channelWeights`. */\n wavelengthIndices?: Uint8Array | Uint16Array;\n /** Spectral integration: per channel (1–4), one finite weight per wavelength. */\n channelWeights?: readonly (readonly number[])[];\n}\n\n/** Validated plan with the resolved chart, illuminant and irradiance scale. Arrays are borrowed. */\nexport interface ChartRadianceBatchPlan {\n chart: ResolvedChartScene;\n illuminant: ResolvedCaptureIlluminant;\n irradianceScale: number;\n queryCount: number;\n /** Output values per query: 1 for radiance queries, the channel count for spectral integration. */\n columns: number;\n mode: \"radiance\" | \"spectral-integral\";\n wavelengthsNanometers: readonly number[];\n channelWeights: readonly (readonly number[])[] | null;\n /** Spectral radiance of one material at a wavelength: the provider's own radianceAt for that material. */\n materialRadiance(material: number, wavelengthNanometers: number): number;\n /** The reference value of one query and output column (radianceAt, and its wavelength-ordered sum). */\n queryValue(points: Float32Array | Float64Array, wavelengthIndices: Uint8Array | Uint16Array | undefined, query: number, column: number): number;\n}\n\nexport function calculateChartRadianceBatchPlan(input: ChartRadianceBatchInput): ChartRadianceBatchPlan {\n const r = requireAllowlistedRecord(input, [\"schemaVersion\", \"scene\", \"illuminant\", \"illuminanceLux\", \"aspect\", \"points\", \"wavelengthsNanometers\",\n \"wavelengthIndices\", \"channelWeights\"], \"Invalid chart radiance batch input.\");\n if (r.schemaVersion !== CHART_RADIANCE_BATCH_SCHEMA_VERSION) throw new InvalidConfigurationError(\"Unsupported chart radiance batch schema.\");\n if (typeof r.aspect !== \"number\" || !(r.aspect > 0 && r.aspect <= Number.MAX_VALUE)) throw new InvalidConfigurationError(\"aspect must be positive.\");\n const chart = resolveChartScene({ scene: r.scene as ChartScene, aspect: r.aspect });\n const illuminant = resolveCaptureIlluminant(r.illuminant as CaptureIlluminant);\n const irradianceScale = calculateIlluminantIrradianceScale(illuminant.shape, r.illuminanceLux as number);\n const L = CHART_RADIANCE_BATCH_LIMITS, points = r.points;\n if (!(points instanceof Float32Array || points instanceof Float64Array) || points.length % 2 !== 0 || points.length / 2 > L.maximumQueries) {\n throw new InvalidConfigurationError(\"points must be an interleaved Float32Array or Float64Array of (u, v) pairs.\");\n }\n for (let i = 0; i < points.length; i++) if (!Number.isFinite(points[i]!)) throw new InvalidConfigurationError(\"Chart points must be finite.\");\n const queryCount = points.length / 2, wavelengths = r.wavelengthsNanometers;\n if (!Array.isArray(wavelengths) || wavelengths.length < 1 || wavelengths.length > L.maximumWavelengths ||\n wavelengths.some(nm => typeof nm !== \"number\" || !Number.isFinite(nm) || nm <= 0)) {\n throw new InvalidConfigurationError(\"wavelengthsNanometers must list 1 to 256 positive wavelengths.\");\n }\n const indices = r.wavelengthIndices, weights = r.channelWeights;\n if ((indices === undefined) === (weights === undefined)) throw new InvalidConfigurationError(\"Give exactly one of wavelengthIndices and channelWeights.\");\n if (indices !== undefined) {\n if (!(indices instanceof Uint8Array || indices instanceof Uint16Array) || indices.length !== queryCount) {\n throw new InvalidConfigurationError(\"wavelengthIndices must hold one index per point.\");\n }\n for (let i = 0; i < queryCount; i++) if (indices[i]! >= wavelengths.length) throw new InvalidConfigurationError(\"A wavelength index is out of range.\");\n } else if (!Array.isArray(weights) || weights.length < 1 || weights.length > L.maximumChannels ||\n weights.some(row => !Array.isArray(row) || row.length !== wavelengths.length || row.some(w => typeof w !== \"number\" || !Number.isFinite(w)))) {\n throw new InvalidConfigurationError(\"channelWeights must hold 1 to 4 rows of one finite weight per wavelength.\");\n }\n // The provider's own radiance function: chart reflectance × scaled illuminant / π, in its float64 order.\n const provider = buildPlanarSceneRadianceProvider({ scene: chart, sceneId: \"chart-radiance-batch\", providerProfileId: \"chart-radiance-batch\", illuminant,\n irradianceScale, geometry: { distanceM: 1, metresPerFrameUnit: 1 }, evidence: [], limitations: [] });\n const channelWeights = weights === undefined ? null : (weights as number[][]).map(row => Object.freeze([...row]));\n const nm = Object.freeze([...(wavelengths as number[])]);\n const materialRadiance = (material: number, wavelength: number): number => {\n const m = chart.materials[material]!;\n const reflectance = m.kind === \"neutral\" ? m.reflectance : m.spectrum.evaluate(wavelength);\n if (m.kind === \"spectrum\" && !(reflectance >= 0 && reflectance <= 1)) throw new InvalidConfigurationError(\"Chart reflectance spectrum left [0, 1].\");\n return reflectance * irradianceScale * illuminant.shape.evaluate(wavelength) / Math.PI;\n };\n return Object.freeze({ chart, illuminant, irradianceScale, queryCount, columns: channelWeights === null ? 1 : channelWeights.length,\n mode: channelWeights === null ? \"radiance\" as const : \"spectral-integral\" as const, wavelengthsNanometers: nm, channelWeights, materialRadiance,\n queryValue(p: Float32Array | Float64Array, w: Uint8Array | Uint16Array | undefined, query: number, column: number): number {\n const u = p[2 * query]!, v = p[2 * query + 1]!;\n if (channelWeights === null) return provider.radianceAt(u, v, nm[w![query]!]!);\n let sum = 0;\n const row = channelWeights[column]!;\n for (let j = 0; j < nm.length; j++) sum += row[j]! * provider.radianceAt(u, v, nm[j]!);\n return sum;\n } });\n}\n\n/** Float64 CPU reference: every query's value(s), row-major (query, column). */\nexport function calculateChartRadianceBatch(input: ChartRadianceBatchInput): { plan: ChartRadianceBatchPlan; values: Float64Array } {\n const plan = calculateChartRadianceBatchPlan(input), values = new Float64Array(plan.queryCount * plan.columns);\n for (let q = 0; q < plan.queryCount; q++) for (let c = 0; c < plan.columns; c++) values[q * plan.columns + c] = plan.queryValue(input.points, input.wavelengthIndices, q, c);\n return { plan, values };\n}\n\n/**\n * Frame points of environment-direction queries on the chart plane, exactly as the planar provider's\n * `evaluateRadiance` computes them: look direction l = −o, plane point l·distance/l.z, in frame units.\n * @param directions - Outgoing unit vectors (scene toward camera), interleaved [x, y, z, …].\n */\nexport function mapEnvironmentDirectionsToChartPoints(input: { directions: Float32Array | Float64Array; distanceM: number; metresPerFrameUnit: number }): Float64Array {\n const r = requireAllowlistedRecord(input, [\"directions\", \"distanceM\", \"metresPerFrameUnit\"], \"Invalid planar direction input.\");\n const d = r.directions, distance = r.distanceM, scale = r.metresPerFrameUnit;\n if (!(d instanceof Float32Array || d instanceof Float64Array) || d.length % 3 !== 0 || typeof distance !== \"number\" || !(distance > 0 && distance <= Number.MAX_VALUE) ||\n typeof scale !== \"number\" || !(scale > 0 && scale <= Number.MAX_VALUE)) {\n throw new InvalidConfigurationError(\"Planar directions need interleaved unit vectors, a positive distance and a positive frame scale.\");\n }\n const points = new Float64Array(d.length / 3 * 2);\n for (let i = 0; i < d.length / 3; i++) {\n const lz = -d[3 * i + 2]!;\n if (!(lz > 0)) throw new InvalidConfigurationError(\"Planar scene query does not point toward the scene plane.\");\n const t = distance / lz;\n const x = -d[3 * i]! * t / scale, y = -d[3 * i + 1]! * t / scale;\n // A grazing direction (lz near 0, e.g. 1e-320) or a non-finite component would give ±Infinity or NaN.\n if (!Number.isFinite(x) || !Number.isFinite(y)) throw new InvalidConfigurationError(\"Planar scene query maps to a non-finite chart point (grazing or non-finite direction).\");\n points[2 * i] = x;\n points[2 * i + 1] = y;\n }\n return points;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"chart-radiance-batch.js","sourceRoot":"","sources":["../../src/facade/chart-radiance-batch.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Batched radiance queries for the engine's procedural chart scenes (#277): many frame points in one\n * call, each answered with spectral radiance at a declared wavelength, or with the spectral integral of\n * that radiance against declared channel weights. This is the float64 CPU reference for the\n * `webgpu-f32` chart-radiance stage (`ImageKernelAccelerator.evaluateChartRadiance`).\n *\n * Every value comes from the chart provider's own `radianceAt` (createPlanarSceneRadianceProvider): a\n * Lambertian reflectance ρ(λ) under the scaled illuminant, L = ρ·k·S(λ)/π. The spectral integral of a\n * query is Σ_j w_cj·L(u, v, λ_j), summed in wavelength order. Charts are uniform-illuminant Lambertian\n * patterns, so a query's integral depends only on its material: the GPU stage uses exactly that.\n *\n * The query shape mirrors a batched provider (one call, queries in, results in the same order). Points\n * are frame units (u right, v up; see chart-scenes.ts); `mapEnvironmentDirectionsToChartPoints` converts\n * environment-direction queries exactly as `evaluateRadiance` does.\n * @see docs/WEBGPU.md, \"Scene radiance on the GPU\".\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { requireAllowlistedRecord } from \"../core/record-validation.js\";\nimport { FULL_RESOLUTION_CEILING_PIXELS, resolveRaisedLimit } from \"../core/pixel-limits.js\";\nimport { resolveChartScene, type ChartScene, type ResolvedChartScene } from \"./chart-scenes.js\";\nimport { buildPlanarSceneRadianceProvider, calculateIlluminantIrradianceScale, resolveCaptureIlluminant, type CaptureIlluminant,\n type ResolvedCaptureIlluminant } from \"./scene-radiance.js\";\n\nexport const CHART_RADIANCE_BATCH_SCHEMA_VERSION = \"0.1.0\" as const;\n/** `maximumQueries` is the default batch limit; a request may raise it with its own `maximumQueries`, up to `ceilingQueries`. */\nexport const CHART_RADIANCE_BATCH_LIMITS = Object.freeze({ maximumQueries: 24_000_000, ceilingQueries: FULL_RESOLUTION_CEILING_PIXELS, maximumWavelengths: 256,\n maximumChannels: 4 });\n\nexport interface ChartRadianceBatchInput {\n schemaVersion: typeof CHART_RADIANCE_BATCH_SCHEMA_VERSION;\n /** An engine chart preset (caller scene functions are not supported here). */\n scene: ChartScene;\n illuminant: CaptureIlluminant;\n illuminanceLux: number;\n /** Frame height / width. */\n aspect: number;\n /** Frame points, interleaved [u0, v0, u1, v1, …]. Finite. */\n points: Float32Array | Float64Array;\n /** The wavelengths the queries use, in nanometres (1–256). */\n wavelengthsNanometers: readonly number[];\n /** Radiance queries: one wavelength index per point. Exactly one of this and `channelWeights`. */\n wavelengthIndices?: Uint8Array | Uint16Array;\n /** Spectral integration: per channel (1–4), one finite weight per wavelength. */\n channelWeights?: readonly (readonly number[])[];\n /**\n * Optional opt-in batch limit: an integer from 1 to `CHART_RADIANCE_BATCH_LIMITS.ceilingQueries`. Default\n * `CHART_RADIANCE_BATCH_LIMITS.maximumQueries` (24 000 000). It does not change the values.\n */\n maximumQueries?: number;\n}\n\n/** Validated plan with the resolved chart, illuminant and irradiance scale. Arrays are borrowed. */\nexport interface ChartRadianceBatchPlan {\n chart: ResolvedChartScene;\n illuminant: ResolvedCaptureIlluminant;\n irradianceScale: number;\n queryCount: number;\n /** Output values per query: 1 for radiance queries, the channel count for spectral integration. */\n columns: number;\n mode: \"radiance\" | \"spectral-integral\";\n wavelengthsNanometers: readonly number[];\n channelWeights: readonly (readonly number[])[] | null;\n /** Spectral radiance of one material at a wavelength: the provider's own radianceAt for that material. */\n materialRadiance(material: number, wavelengthNanometers: number): number;\n /** The reference value of one query and output column (radianceAt, and its wavelength-ordered sum). */\n queryValue(points: Float32Array | Float64Array, wavelengthIndices: Uint8Array | Uint16Array | undefined, query: number, column: number): number;\n}\n\nexport function calculateChartRadianceBatchPlan(input: ChartRadianceBatchInput): ChartRadianceBatchPlan {\n const r = requireAllowlistedRecord(input, [\"schemaVersion\", \"scene\", \"illuminant\", \"illuminanceLux\", \"aspect\", \"points\", \"wavelengthsNanometers\",\n \"wavelengthIndices\", \"channelWeights\", \"maximumQueries\"], \"Invalid chart radiance batch input.\");\n if (r.schemaVersion !== CHART_RADIANCE_BATCH_SCHEMA_VERSION) throw new InvalidConfigurationError(\"Unsupported chart radiance batch schema.\");\n if (typeof r.aspect !== \"number\" || !(r.aspect > 0 && r.aspect <= Number.MAX_VALUE)) throw new InvalidConfigurationError(\"aspect must be positive.\");\n const chart = resolveChartScene({ scene: r.scene as ChartScene, aspect: r.aspect });\n const illuminant = resolveCaptureIlluminant(r.illuminant as CaptureIlluminant);\n const irradianceScale = calculateIlluminantIrradianceScale(illuminant.shape, r.illuminanceLux as number);\n const L = CHART_RADIANCE_BATCH_LIMITS, points = r.points;\n const maximumQueries = resolveRaisedLimit(r.maximumQueries, L.maximumQueries, L.ceilingQueries,\n \"Chart radiance batch maximumQueries must be an integer from 1 to \" + L.ceilingQueries + \".\");\n if (!(points instanceof Float32Array || points instanceof Float64Array) || points.length % 2 !== 0 || points.length / 2 > maximumQueries) {\n throw new InvalidConfigurationError(\"points must be an interleaved Float32Array or Float64Array of (u, v) pairs.\");\n }\n for (let i = 0; i < points.length; i++) if (!Number.isFinite(points[i]!)) throw new InvalidConfigurationError(\"Chart points must be finite.\");\n const queryCount = points.length / 2, wavelengths = r.wavelengthsNanometers;\n if (!Array.isArray(wavelengths) || wavelengths.length < 1 || wavelengths.length > L.maximumWavelengths ||\n wavelengths.some(nm => typeof nm !== \"number\" || !Number.isFinite(nm) || nm <= 0)) {\n throw new InvalidConfigurationError(\"wavelengthsNanometers must list 1 to 256 positive wavelengths.\");\n }\n const indices = r.wavelengthIndices, weights = r.channelWeights;\n if ((indices === undefined) === (weights === undefined)) throw new InvalidConfigurationError(\"Give exactly one of wavelengthIndices and channelWeights.\");\n if (indices !== undefined) {\n if (!(indices instanceof Uint8Array || indices instanceof Uint16Array) || indices.length !== queryCount) {\n throw new InvalidConfigurationError(\"wavelengthIndices must hold one index per point.\");\n }\n for (let i = 0; i < queryCount; i++) if (indices[i]! >= wavelengths.length) throw new InvalidConfigurationError(\"A wavelength index is out of range.\");\n } else if (!Array.isArray(weights) || weights.length < 1 || weights.length > L.maximumChannels ||\n weights.some(row => !Array.isArray(row) || row.length !== wavelengths.length || row.some(w => typeof w !== \"number\" || !Number.isFinite(w)))) {\n throw new InvalidConfigurationError(\"channelWeights must hold 1 to 4 rows of one finite weight per wavelength.\");\n }\n // The provider's own radiance function: chart reflectance × scaled illuminant / π, in its float64 order.\n const provider = buildPlanarSceneRadianceProvider({ scene: chart, sceneId: \"chart-radiance-batch\", providerProfileId: \"chart-radiance-batch\", illuminant,\n irradianceScale, geometry: { distanceM: 1, metresPerFrameUnit: 1 }, evidence: [], limitations: [] });\n const channelWeights = weights === undefined ? null : (weights as number[][]).map(row => Object.freeze([...row]));\n const nm = Object.freeze([...(wavelengths as number[])]);\n const materialRadiance = (material: number, wavelength: number): number => {\n const m = chart.materials[material]!;\n const reflectance = m.kind === \"neutral\" ? m.reflectance : m.spectrum.evaluate(wavelength);\n if (m.kind === \"spectrum\" && !(reflectance >= 0 && reflectance <= 1)) throw new InvalidConfigurationError(\"Chart reflectance spectrum left [0, 1].\");\n return reflectance * irradianceScale * illuminant.shape.evaluate(wavelength) / Math.PI;\n };\n return Object.freeze({ chart, illuminant, irradianceScale, queryCount, columns: channelWeights === null ? 1 : channelWeights.length,\n mode: channelWeights === null ? \"radiance\" as const : \"spectral-integral\" as const, wavelengthsNanometers: nm, channelWeights, materialRadiance,\n queryValue(p: Float32Array | Float64Array, w: Uint8Array | Uint16Array | undefined, query: number, column: number): number {\n const u = p[2 * query]!, v = p[2 * query + 1]!;\n if (channelWeights === null) return provider.radianceAt(u, v, nm[w![query]!]!);\n let sum = 0;\n const row = channelWeights[column]!;\n for (let j = 0; j < nm.length; j++) sum += row[j]! * provider.radianceAt(u, v, nm[j]!);\n return sum;\n } });\n}\n\n/** Float64 CPU reference: every query's value(s), row-major (query, column). */\nexport function calculateChartRadianceBatch(input: ChartRadianceBatchInput): { plan: ChartRadianceBatchPlan; values: Float64Array } {\n const plan = calculateChartRadianceBatchPlan(input), values = new Float64Array(plan.queryCount * plan.columns);\n for (let q = 0; q < plan.queryCount; q++) for (let c = 0; c < plan.columns; c++) values[q * plan.columns + c] = plan.queryValue(input.points, input.wavelengthIndices, q, c);\n return { plan, values };\n}\n\n/**\n * Frame points of environment-direction queries on the chart plane, exactly as the planar provider's\n * `evaluateRadiance` computes them: look direction l = −o, plane point l·distance/l.z, in frame units.\n * @param directions - Outgoing unit vectors (scene toward camera), interleaved [x, y, z, …].\n */\nexport function mapEnvironmentDirectionsToChartPoints(input: { directions: Float32Array | Float64Array; distanceM: number; metresPerFrameUnit: number }): Float64Array {\n const r = requireAllowlistedRecord(input, [\"directions\", \"distanceM\", \"metresPerFrameUnit\"], \"Invalid planar direction input.\");\n const d = r.directions, distance = r.distanceM, scale = r.metresPerFrameUnit;\n if (!(d instanceof Float32Array || d instanceof Float64Array) || d.length % 3 !== 0 || typeof distance !== \"number\" || !(distance > 0 && distance <= Number.MAX_VALUE) ||\n typeof scale !== \"number\" || !(scale > 0 && scale <= Number.MAX_VALUE)) {\n throw new InvalidConfigurationError(\"Planar directions need interleaved unit vectors, a positive distance and a positive frame scale.\");\n }\n const points = new Float64Array(d.length / 3 * 2);\n for (let i = 0; i < d.length / 3; i++) {\n const lz = -d[3 * i + 2]!;\n if (!(lz > 0)) throw new InvalidConfigurationError(\"Planar scene query does not point toward the scene plane.\");\n const t = distance / lz;\n const x = -d[3 * i]! * t / scale, y = -d[3 * i + 1]! * t / scale;\n // A grazing direction (lz near 0, e.g. 1e-320) or a non-finite component would give ±Infinity or NaN.\n if (!Number.isFinite(x) || !Number.isFinite(y)) throw new InvalidConfigurationError(\"Planar scene query maps to a non-finite chart point (grazing or non-finite direction).\");\n points[2 * i] = x;\n points[2 * i + 1] = y;\n }\n return points;\n}\n"]}
|
|
@@ -129,7 +129,7 @@ export interface SimulateCaptureOptions {
|
|
|
129
129
|
* Opt-in (2.1) diffraction blur of an ideal, aberration-free, in-focus lens with a circular pupil at the
|
|
130
130
|
* capture's resolved f-number: the engine builds the Airy kernels (`createDiffractionLimitedPsfProfile`)
|
|
131
131
|
* on the site pitch. `kernelRadiusSamples` (0–32) sets the kernel window; default: the third dark ring at
|
|
132
|
-
* the longest spectral node. Not combinable with `psf` or `pupilSampling`. Default off.
|
|
132
|
+
* the longest spectral node, capped at 32 sites. Not combinable with `psf` or `pupilSampling`. Default off.
|
|
133
133
|
*/
|
|
134
134
|
diffraction?: SimulateCaptureLensDiffraction;
|
|
135
135
|
};
|
|
@@ -184,6 +184,13 @@ export interface SimulateCaptureOptions {
|
|
|
184
184
|
dng?: {
|
|
185
185
|
capturedAtUtc?: string;
|
|
186
186
|
};
|
|
187
|
+
/**
|
|
188
|
+
* Opt-in large images: the most native sensor sites (the output plus the demosaic margin on each side) the
|
|
189
|
+
* capture may allocate, an integer up to `NATIVE_RAW_LIMITS.ceilingPixels` (2^27). With it, `width` and
|
|
190
|
+
* `height` may each reach 16 384 sites including the margin; without it they stay at most 4094. Time and
|
|
191
|
+
* memory grow with the pixel count (see "Large images" in the quick start); browsers may fail at large sizes.
|
|
192
|
+
*/
|
|
193
|
+
maximumPixels?: number;
|
|
187
194
|
};
|
|
188
195
|
/** Camera motion and shutter type. Default: still camera, global electronic shutter. */
|
|
189
196
|
motion?: SimulateCaptureMotion;
|