mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
fix(engine): Linux GPU path uses deprecated EGL + NVENC probe fails on data-center GPUs (#1504)
* fix(engine): use ANGLE-EGL for Linux GPU path, bump NVENC probe size Chrome 131+ rejects --use-gl=egl in headless shell; the GPU process exits and the renderer silently falls back to SwiftShader. Switch to (gl=angle, angle=gl-egl) which is on the headless-shell allowlist, and add --ignore-gpu-blocklist + --disable-software-rasterizer so data-center GPUs (L4/T4/A10) are not blocked. Also bump the NVENC probe frame from 16×16 to 320×240 — NVIDIA data-center cards require ≥257 on each dimension and reject the smaller size with "Frame Dimension less than the minimum supported value", causing the encoder probe to silently fall back to libx264. Closes #1493 * fix(engine): address review feedback — probe test, observability, comments - Export getProbeArgs and add test pinning 320×240 probe dimensions across all 5 GPU encoder backends (nvenc/videotoolbox/vaapi/qsv/amf) - Add driver/SKU rationale comment on the probe size constant with context about NVIDIA data-center card behavior vs documented minimums - Add rationale comment on --ignore-gpu-blocklist (operator opted into hardware mode explicitly) - Log resolved GL flags at browser launch for GPU fallback observability
This commit is contained in:
@@ -45,11 +45,13 @@ describe("buildChromeArgs browser GPU mode", () => {
|
|||||||
expect(args).not.toContain("--use-angle=swiftshader");
|
expect(args).not.toContain("--use-angle=swiftshader");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses EGL for hardware browser GPU mode on Linux", () => {
|
it("uses ANGLE-EGL for hardware browser GPU mode on Linux", () => {
|
||||||
const args = buildChromeArgs({ ...base, platform: "linux" }, { browserGpuMode: "hardware" });
|
const args = buildChromeArgs({ ...base, platform: "linux" }, { browserGpuMode: "hardware" });
|
||||||
expect(args).toContain("--use-gl=egl");
|
expect(args).toContain("--use-gl=angle");
|
||||||
|
expect(args).toContain("--use-angle=gl-egl");
|
||||||
expect(args).toContain("--enable-gpu-rasterization");
|
expect(args).toContain("--enable-gpu-rasterization");
|
||||||
expect(args).not.toContain("--use-gl=angle");
|
expect(args).toContain("--ignore-gpu-blocklist");
|
||||||
|
expect(args).toContain("--disable-software-rasterizer");
|
||||||
expect(args).not.toContain("--use-angle=swiftshader");
|
expect(args).not.toContain("--use-angle=swiftshader");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -378,8 +378,11 @@ async function launchBrowser(
|
|||||||
});
|
});
|
||||||
|
|
||||||
const browserVersion = await browser.version().catch(() => "unknown");
|
const browserVersion = await browser.version().catch(() => "unknown");
|
||||||
|
const gpuFlags = chromeArgs.filter(
|
||||||
|
(a) => a.startsWith("--use-gl=") || a.startsWith("--use-angle="),
|
||||||
|
);
|
||||||
console.log(
|
console.log(
|
||||||
`[BrowserManager] Browser launched (${browserVersion}, ${captureMode}, headlessShell=${!!headlessShell}, platform=${process.platform})`,
|
`[BrowserManager] Browser launched (${browserVersion}, ${captureMode}, gl=${gpuFlags.join(" ") || "default"}, headlessShell=${!!headlessShell}, platform=${process.platform})`,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (captureMode === "beginframe") {
|
if (captureMode === "beginframe") {
|
||||||
@@ -650,7 +653,17 @@ function getBrowserGpuArgs(
|
|||||||
case "win32":
|
case "win32":
|
||||||
return ["--use-gl=angle", "--use-angle=d3d11", "--enable-gpu-rasterization"];
|
return ["--use-gl=angle", "--use-angle=d3d11", "--enable-gpu-rasterization"];
|
||||||
case "linux":
|
case "linux":
|
||||||
return ["--use-gl=egl", "--enable-gpu-rasterization"];
|
// Chrome 131+ headless shell only accepts (gl=angle, angle=gl-egl);
|
||||||
|
// the old --use-gl=egl causes the GPU process to exit silently.
|
||||||
|
// --ignore-gpu-blocklist: the operator explicitly opted into
|
||||||
|
// browserGpuMode="hardware", so trust their driver/GPU choice.
|
||||||
|
return [
|
||||||
|
"--use-gl=angle",
|
||||||
|
"--use-angle=gl-egl",
|
||||||
|
"--enable-gpu-rasterization",
|
||||||
|
"--ignore-gpu-blocklist",
|
||||||
|
"--disable-software-rasterizer",
|
||||||
|
];
|
||||||
default:
|
default:
|
||||||
return ["--enable-gpu-rasterization"];
|
return ["--enable-gpu-rasterization"];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
|||||||
import {
|
import {
|
||||||
getCompiledGpuEncoders,
|
getCompiledGpuEncoders,
|
||||||
getGpuEncoderName,
|
getGpuEncoderName,
|
||||||
|
getProbeArgs,
|
||||||
mapPresetForGpuEncoder,
|
mapPresetForGpuEncoder,
|
||||||
selectUsableGpuEncoder,
|
selectUsableGpuEncoder,
|
||||||
} from "./gpuEncoder.js";
|
} from "./gpuEncoder.js";
|
||||||
@@ -127,3 +128,13 @@ describe("mapPresetForGpuEncoder", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("getProbeArgs", () => {
|
||||||
|
it("uses 320x240 probe dimensions for all GPU encoders", () => {
|
||||||
|
const encoders = ["nvenc", "videotoolbox", "vaapi", "qsv", "amf"] as const;
|
||||||
|
for (const encoder of encoders) {
|
||||||
|
const args = getProbeArgs(encoder);
|
||||||
|
expect(args).toContain("color=size=320x240:rate=1:duration=1");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -108,7 +108,17 @@ export function getGpuEncoderName(encoder: GpuEncoder, codec: "h264" | "h265"):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProbeArgs(encoder: ConcreteGpuEncoder): string[] {
|
// Minimum probe dimensions must clear every GPU encoder's hardware minimum.
|
||||||
|
// NVIDIA data-center SKUs (L4/T4/A10/A100) reject frames below ~257px on
|
||||||
|
// either dimension with "Frame Dimension less than the minimum supported
|
||||||
|
// value" (observed on driver 595.58.03, CUDA 13.2). The documented SDK
|
||||||
|
// minimums (145×49 H.264, 129×33 HEVC) are lower, but the driver enforces
|
||||||
|
// a stricter per-SKU alignment. 320×240 clears all known GPU encoder
|
||||||
|
// minimums (NVENC, VideoToolbox, VAAPI, QSV, AMF) while staying cheap.
|
||||||
|
const GPU_PROBE_WIDTH = 320;
|
||||||
|
const GPU_PROBE_HEIGHT = 240;
|
||||||
|
|
||||||
|
export function getProbeArgs(encoder: ConcreteGpuEncoder): string[] {
|
||||||
const args = [
|
const args = [
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-loglevel",
|
"-loglevel",
|
||||||
@@ -116,7 +126,7 @@ function getProbeArgs(encoder: ConcreteGpuEncoder): string[] {
|
|||||||
"-f",
|
"-f",
|
||||||
"lavfi",
|
"lavfi",
|
||||||
"-i",
|
"-i",
|
||||||
"color=size=16x16:rate=1:duration=1",
|
`color=size=${GPU_PROBE_WIDTH}x${GPU_PROBE_HEIGHT}:rate=1:duration=1`,
|
||||||
"-frames:v",
|
"-frames:v",
|
||||||
"1",
|
"1",
|
||||||
"-an",
|
"-an",
|
||||||
|
|||||||
Reference in New Issue
Block a user