Skip to content

Commit ebfb8fb

Browse files
committed
revert: stop releasing a WebGL context when its clip's window has ended
1 parent 346f0e4 commit ebfb8fb

2 files changed

Lines changed: 76 additions & 5 deletions

File tree

‎packages/engine/src/services/frameCapture.ts‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import {
3434

3535
import { readReferenceBackground } from "./referenceBackground.js";
3636
import { holdRenderFrameVideos } from "./renderFrameVideoHold.js";
37-
import { recordWebglContexts, releaseEndedWebglContexts } from "./webglRelease.js";
3837
import { asDrawElementCaptureFailure, DrawElementCaptureError } from "./drawElementCaptureError.js";
3938
import { encodePng } from "../utils/alphaBlit.js";
4039
import {
@@ -1643,7 +1642,6 @@ async function constructCaptureSession(
16431642
}
16441643
});
16451644
await installMediaPageHooks(page, options);
1646-
await page.evaluateOnNewDocument(recordWebglContexts);
16471645
// Fast capture: record accelerated canvases (webgl/webgl2/webgpu) and force
16481646
// preserveDrawingBuffer before any page script can create a context — their
16491647
// paint records freeze at the first frame, so captureDrawElementFrame
@@ -3294,8 +3292,6 @@ async function prepareFrameForCapture(
32943292
session.captureStep = "seeking the timeline";
32953293
const hasPendingComposite = await seekPageTimeline(page, quantizedTime, seekOptions);
32963294

3297-
await releaseEndedWebglContexts(page, quantizedTime);
3298-
32993295
session.captureStep = "decoding CSS background images";
33003296
await decodeDynamicCssBackgroundImages(page);
33013297

‎packages/engine/src/services/webglRelease.test.ts‎

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,58 @@
1-
import { afterEach, describe, expect, it } from "vitest";
1+
import { afterEach, describe, expect, it, vi } from "vitest";
2+
import { mkdtempSync, rmSync } from "node:fs";
3+
import { tmpdir } from "node:os";
4+
import { join } from "node:path";
25
import type { Page } from "puppeteer-core";
6+
import { captureFrameToBuffer, createCaptureSession } from "./frameCapture.js";
7+
import { pageScreenshotCapture } from "./screenshotService.js";
38
import { releaseEndedWebglContexts } from "./webglRelease.js";
49

10+
const ended = { start: 0, end: 3 };
11+
const lostByCapture: string[] = [];
12+
const hiddenEndedClip = {
13+
hasAttribute: (n: string) => n === "data-hf-clip-hidden",
14+
parentElement: null,
15+
};
16+
17+
vi.mock("./browserManager.js", async (importOriginal) => ({
18+
...(await importOriginal<typeof import("./browserManager.js")>()),
19+
resolveBrowserGpuMode: async () => "hardware",
20+
acquireBrowser: async () => ({
21+
captureMode: "screenshot",
22+
browser: {
23+
version: async () => "Chrome/150.0.0.0",
24+
newPage: async () => ({
25+
mainFrame: () => ({}),
26+
evaluateOnNewDocument: async () => {},
27+
setViewport: async () => {},
28+
evaluate: async (fn: unknown, ...args: unknown[]) => {
29+
if (typeof fn !== "function" || !String(fn).includes("__hf_gl_contexts"))
30+
return undefined;
31+
const ctx = {
32+
getExtension: () => ({ loseContext: () => lostByCapture.push("3d") }),
33+
};
34+
const previous = globalThis.window;
35+
Object.assign(globalThis, {
36+
window: {
37+
__hf_gl_contexts: [{ canvas: { ...hiddenEndedClip }, ctx }],
38+
__hf: { clipWindow: () => ended },
39+
},
40+
});
41+
try {
42+
return await (fn as (...a: unknown[]) => unknown)(...args);
43+
} finally {
44+
Object.assign(globalThis, { window: previous });
45+
}
46+
},
47+
}),
48+
},
49+
}),
50+
}));
51+
vi.mock("./screenshotService.js", async (importOriginal) => ({
52+
...(await importOriginal<typeof import("./screenshotService.js")>()),
53+
pageScreenshotCapture: vi.fn(),
54+
}));
55+
556
type Node = {
657
hasAttribute: (n: string) => boolean;
758
parentElement: Node | null;
@@ -93,3 +144,27 @@ describe("releaseEndedWebglContexts", () => {
93144
expect(lost).toEqual([]);
94145
});
95146
});
147+
148+
describe("capturing a frame", () => {
149+
it("a WebGL canvas in a hidden clip whose window has ended keeps its context (never loseContext)", async () => {
150+
const dir = mkdtempSync(join(tmpdir(), "hf-webgl-keep-"));
151+
try {
152+
vi.mocked(pageScreenshotCapture).mockResolvedValue(Buffer.from("frame"));
153+
const capture = await createCaptureSession(
154+
"http://localhost:0",
155+
dir,
156+
{ width: 320, height: 180, fps: { num: 30, den: 1 }, format: "jpeg" },
157+
null,
158+
{ forceScreenshot: true },
159+
);
160+
capture.isInitialized = true;
161+
lostByCapture.length = 0;
162+
163+
await captureFrameToBuffer(capture, 0, 5);
164+
165+
expect(lostByCapture).toEqual([]);
166+
} finally {
167+
rmSync(dir, { recursive: true, force: true });
168+
}
169+
});
170+
});

0 commit comments

Comments
 (0)