mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-31 19:06:14 +00:00
fix(engine): a GPU probe cancelled by its caller no longer sets software mode for the process (#6541)
The GPU probe's answer is kept for the whole process and the first caller's probe is the one every later caller waits on. When that first caller cancelled it (a prelaunched browser dropped, a stopping check), the probe died with "This operation was aborted", and that cancellation was kept as the answer: every browser the process launched after it ran in software mode, with a log line blaming the GPU probe. A cancelled probe is now forgotten and the next caller probes again.
This commit is contained in:
@@ -714,6 +714,21 @@ describe("resolveBrowserGpuMode", () => {
|
||||
expect(close).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("does not keep a probe its own caller cancelled as the answer for the process", async () => {
|
||||
setMockWebGlProbe({ hasWebGL: true, vendor: "NVIDIA", renderer: "NVIDIA" });
|
||||
const cancelled = {
|
||||
launch: async () => {
|
||||
throw new DOMException("This operation was aborted", "AbortError");
|
||||
},
|
||||
close: vi.fn(),
|
||||
};
|
||||
const first = resolveBrowserGpuMode("auto", { probeLifecycle: cancelled });
|
||||
const second = resolveBrowserGpuMode("auto");
|
||||
await expect(second).resolves.toBe("hardware");
|
||||
await first;
|
||||
await expect(resolveBrowserGpuMode("auto")).resolves.toBe("hardware");
|
||||
});
|
||||
|
||||
it("passes 'software' through unchanged without probing", async () => {
|
||||
const mode = await resolveBrowserGpuMode("software");
|
||||
expect(mode).toBe("software");
|
||||
|
||||
@@ -551,6 +551,7 @@ export const _closeBrowserAfterFailedProbeForTests = closeBrowserAfterFailedProb
|
||||
interface GpuProbeOutcome {
|
||||
mode: "software" | "hardware";
|
||||
cause?: "no-gpu" | "probe-error";
|
||||
aborted?: true;
|
||||
/** Under WSL, what we checked on its GPU path (see describeWslGpuAccess). */
|
||||
wslAccess?: string[];
|
||||
/** Under WSL, Chrome reached the GPU only without WSLg's WAYLAND_DISPLAY. */
|
||||
@@ -649,7 +650,8 @@ async function probeWebGlMode(
|
||||
return resolved === "hardware" ? { mode: "hardware" } : { mode: "software", cause: "no-gpu" };
|
||||
} catch (err) {
|
||||
logResolvedBrowserGpuMode("software", label + formatProbeFailure(err));
|
||||
return { mode: "software", cause: "probe-error" };
|
||||
const aborted = err instanceof Error && err.name === "AbortError";
|
||||
return { mode: "software", cause: "probe-error", ...(aborted && { aborted }) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -717,15 +719,25 @@ function wslAccess(options: GpuProbeOptions): Pick<GpuProbeOutcome, "wslAccess">
|
||||
* safe failure mode; misclassifying toward hardware would error on the real
|
||||
* render.
|
||||
*/
|
||||
async function sharedGpuProbe(options: GpuProbeOptions): Promise<GpuProbeOutcome> {
|
||||
const shared = (_autoBrowserGpuModeCache ??= probeAutoBrowserGpuMode(options));
|
||||
const outcome = await shared;
|
||||
if (!outcome.aborted) return outcome;
|
||||
if (_autoBrowserGpuModeCache === shared) _autoBrowserGpuModeCache = undefined;
|
||||
const own = await probeAutoBrowserGpuMode(options);
|
||||
if (!own.aborted) _autoBrowserGpuModeCache ??= Promise.resolve(own);
|
||||
return own;
|
||||
}
|
||||
|
||||
export function resolveBrowserGpuMode(
|
||||
mode: EngineConfig["browserGpuMode"],
|
||||
options: GpuProbeOptions = {},
|
||||
): Promise<"software" | "hardware"> {
|
||||
if (mode === "software") return Promise.resolve(mode);
|
||||
|
||||
_autoBrowserGpuModeCache ??= probeAutoBrowserGpuMode(options);
|
||||
const probe = sharedGpuProbe(options);
|
||||
if (mode === "auto") {
|
||||
return _autoBrowserGpuModeCache.then((probed) => {
|
||||
return probe.then((probed) => {
|
||||
if (probed.mode === "software" && probed.wslAccess && !_wslSoftwareNoteLogged) {
|
||||
_wslSoftwareNoteLogged = true;
|
||||
console.error(buildWslSoftwareNote(probed));
|
||||
@@ -734,7 +746,7 @@ export function resolveBrowserGpuMode(
|
||||
});
|
||||
}
|
||||
|
||||
return _autoBrowserGpuModeCache.then((probed) => {
|
||||
return probe.then((probed) => {
|
||||
// Warn once per cache lifetime, not once per caller: `createCaptureSession`
|
||||
// resolves the mode for the probe browser AND every parallel worker, so
|
||||
// an un-deduplicated warning prints N+1 times and buries itself.
|
||||
|
||||
Reference in New Issue
Block a user