Files
micarrsim/packages/webgpu-kernels/compute.js
T
2026-08-28 11:26:19 +09:00

59 lines
2.0 KiB
JavaScript

import { computeDasMap } from "../acoustics-core/das.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.
*/
export async function computeDasWithBackend(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}`,
);
}
}
}