@@ -27,37 +27,22 @@ export async function resolveCaptureBrowserGpuMode(
2727// existing CLI imports don't need to change their module path.
2828export { compositionRequiresWebGpu , assertWebGpuAdapterAvailable } from "@hyperframes/engine" ;
2929
30+ const COLOR_GRADING_ATTR_RE = new RegExp ( `\\s${ HF_COLOR_GRADING_ATTR } [\\s=>]` , "i" ) ;
31+
3032export function compositionUsesColorGrading ( html : string ) : boolean {
31- const escapedAttr = HF_COLOR_GRADING_ATTR . replace ( / [ - / \\ ^ $ * + ? . ( ) | [ \] { } ] / g, "\\$&" ) ;
32- return new RegExp ( `\\s${ escapedAttr } (?:\\s|=|>)` , "i" ) . test ( html ) ;
33+ return COLOR_GRADING_ATTR_RE . test ( html ) ;
3334}
3435
3536const COLOR_GRADING_GPU_STALL_WARNING =
36- `This composition uses ${ HF_COLOR_GRADING_ATTR } , but no hardware GPU was detected — ` +
37- "the browser will render on the SwiftShader/software WebGL fallback. Color grading's " +
38- "per-element canvas readback has no fast path under software WebGL: it has been measured " +
39- "at roughly 40x slower than an ungraded composition, which is easily enough to exceed the " +
40- "navigation/render-ready timeout, or to make check/render painfully slow even once past it. " +
41- "If this run is unexpectedly slow or times out, try a much larger --timeout, run on a host " +
42- "with a real GPU, or preprocess to monochrome derivatives with grading intensity 0 before " +
43- "capturing with --browser-gpu to skip the expensive per-frame grading pass entirely." ;
37+ `This composition uses ${ HF_COLOR_GRADING_ATTR } , but no hardware GPU was detected, so the ` +
38+ "browser renders with software WebGL (SwiftShader). Color grading's per-frame canvas readback " +
39+ "is far slower there and can exceed the navigation timeout. If this run is slow or " +
40+ "times out, raise --timeout or run on a host with a real GPU." ;
4441
4542/**
46- * Preflight for a known SwiftShader limitation (not a hyperframes bug): a
47- * per-element color-grading canvas pays a synchronous GPU-stall readback cost
48- * that software WebGL has no fast path for, ~40x slower than an ungraded
49- * composition in measured practice. `requestedMode: "software"` is a
50- * deliberate, already-informed choice and is not warned about; `"auto"` /
51- * `"hardware"` both expect speed, so a silent fallback to software there is
52- * exactly the surprise this call is meant to catch before capture starts.
53- * Reuses `resolveCaptureBrowserGpuMode`'s cached probe (forcing `"auto"` to
54- * get the ground-truth answer even when the caller requested `"hardware"`,
55- * which always reports back `"hardware"` verbatim) — resolved against the
56- * same `ensureBrowser()` executable path a subsequent real launch will use,
57- * so this doesn't seed the shared cache with a different browser's probe.
58- * Best-effort: any probe failure here is treated as "nothing to warn about"
59- * rather than failing the caller — the real launch will surface a genuine
60- * browser problem on its own.
43+ * Warns before capture when a graded composition will run on software WebGL. An explicit
44+ * "software" request is a deliberate choice and stays silent; "hardware" is reported verbatim
45+ * by the engine, so probe "auto" for the real answer. Shares the engine's cached probe.
6146 */
6247export async function detectColorGradingGpuStallRisk (
6348 html : string ,
@@ -70,6 +55,7 @@ export async function detectColorGradingGpuStallRisk(
7055 const actualMode = await resolveCaptureBrowserGpuMode ( "auto" , browser . executablePath ) ;
7156 return actualMode === "software" ? COLOR_GRADING_GPU_STALL_WARNING : null ;
7257 } catch {
58+ // Best-effort: the real launch surfaces a genuine browser failure.
7359 return null ;
7460 }
7561}
0 commit comments