113 lines
4.1 KiB
JavaScript
113 lines
4.1 KiB
JavaScript
import { computeDasMap } from "../acoustics-core/das.js";
|
|
import { computeGccPhatMap } from "../acoustics-core/gcc-phat.js";
|
|
import { computeLocalizationMap } from "../acoustics-core/localization.js";
|
|
import {
|
|
isDasAlgorithm,
|
|
requireLocalizationAlgorithmDefinition,
|
|
} from "../acoustics-core/localization-algorithms.js";
|
|
import { computeDasWebGpu } from "./das.js";
|
|
import { isRecoverableWebGpuError } from "./device.js";
|
|
|
|
function createAbortError(signal) {
|
|
if (signal?.reason instanceof Error && signal.reason.name === "AbortError") return signal.reason;
|
|
const error = new Error("DAS 계산이 취소되었습니다.");
|
|
error.name = "AbortError";
|
|
return error;
|
|
}
|
|
|
|
function throwIfAborted(signal) {
|
|
if (signal?.aborted) throw createAbortError(signal);
|
|
}
|
|
|
|
/**
|
|
* Execute the requested DAS backend. `auto` falls back only for typed WebGPU
|
|
* operational errors; invalid inputs and AbortError remain visible to callers.
|
|
*/
|
|
async function computeDasBackend(options, dependencies = {}) {
|
|
const computeGpu = dependencies.computeGpu ?? computeDasWebGpu;
|
|
const computeCpu = dependencies.computeCpu ?? computeDasMap;
|
|
const requestedBackend = options?.experiment?.beamforming?.backend ?? "auto";
|
|
|
|
if (requestedBackend === "cpu") return computeCpu(options);
|
|
if (requestedBackend === "webgpu") return computeGpu(options);
|
|
if (requestedBackend !== "auto") {
|
|
throw new TypeError(`지원하지 않는 DAS backend입니다: ${requestedBackend}`);
|
|
}
|
|
|
|
try {
|
|
return await computeGpu(options);
|
|
} catch (gpuError) {
|
|
if (!isRecoverableWebGpuError(gpuError)) throw gpuError;
|
|
throwIfAborted(options.signal);
|
|
options.onFallback?.({ from: "webgpu", to: "cpu", error: gpuError });
|
|
throwIfAborted(options.signal);
|
|
try {
|
|
const cpuResult = await computeCpu(options);
|
|
return {
|
|
...cpuResult,
|
|
requestedBackend: "auto",
|
|
fallback: {
|
|
from: "webgpu",
|
|
code: gpuError.code,
|
|
message: gpuError.message,
|
|
},
|
|
};
|
|
} catch (cpuError) {
|
|
if (cpuError?.name === "AbortError") throw cpuError;
|
|
throwIfAborted(options.signal);
|
|
throw new AggregateError(
|
|
[gpuError, cpuError],
|
|
`WebGPU 실행 실패 후 CPU fallback도 실패했습니다: ${cpuError.message}`,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute a DAS-family algorithm with the requested CPU/WebGPU policy.
|
|
* Conventional DAS callers can keep using this backwards-compatible entry.
|
|
*/
|
|
export async function computeDasWithBackend(options, dependencies = {}) {
|
|
const algorithm = requireLocalizationAlgorithmDefinition(
|
|
options?.experiment?.beamforming?.algorithm,
|
|
);
|
|
if (!isDasAlgorithm(algorithm.id)) {
|
|
throw new RangeError(
|
|
`computeDasWithBackend does not implement ${algorithm.id}.`,
|
|
);
|
|
}
|
|
return computeDasBackend(options, dependencies);
|
|
}
|
|
|
|
/**
|
|
* Execute any registered localization algorithm. CPU-only algorithms use
|
|
* their portable implementation for both `auto` and `cpu`; an explicit
|
|
* WebGPU request is rejected instead of silently changing the requested
|
|
* backend.
|
|
*/
|
|
export async function computeLocalizationWithBackend(options, dependencies = {}) {
|
|
const algorithm = requireLocalizationAlgorithmDefinition(
|
|
options?.experiment?.beamforming?.algorithm,
|
|
);
|
|
if (isDasAlgorithm(algorithm.id)) {
|
|
return computeDasBackend(options, dependencies);
|
|
}
|
|
if (algorithm.id !== "gcc-phat" && algorithm.id !== "music") {
|
|
throw new RangeError("No backend dispatcher is registered for " + algorithm.id + ".");
|
|
}
|
|
|
|
const requestedBackend = options?.experiment?.beamforming?.backend ?? "auto";
|
|
if (requestedBackend === "webgpu") {
|
|
throw new TypeError(
|
|
`${algorithm.label} currently supports only the CPU backend; choose auto or cpu.`,
|
|
);
|
|
}
|
|
if (requestedBackend !== "auto" && requestedBackend !== "cpu") {
|
|
throw new TypeError(`unsupported localization backend: ${requestedBackend}`);
|
|
}
|
|
const computeCpu = algorithm.id === "gcc-phat"
|
|
? dependencies.computeGccCpu ?? dependencies.computeCpu ?? computeGccPhatMap
|
|
: dependencies.computeMusicCpu ?? dependencies.computeCpu ?? computeLocalizationMap;
|
|
return computeCpu(options);
|
|
}
|