fix(cli): the WebGL draw recorder never stops a draw and judges each canvas once per sample

This commit is contained in:
Miguel Angel Simon Sierra
2026-11-03 18:33:33 -05:00
parent 7930bd4622
commit b14c5dd56a
2 changed files with 46 additions and 2 deletions
@@ -2209,9 +2209,11 @@
// Canvases that drew WebGL while hidden since the last audit, judged when the draw happens; the author's own
// hf-seek loop decides what draws.
const webglDraws = (window.__hyperframesWebglDraws ??= new Set());
let judgedThisSample = new WeakSet();
const drawGate = Symbol.for("hyperframes.webglDrawGate");
window.__hyperframesRecordWebglDraw = (canvas) => {
if (!canvas || webglDraws.has(canvas)) return;
if (typeof canvas?.closest !== "function" || judgedThisSample.has(canvas)) return;
judgedThisSample.add(canvas);
if (canvas.closest(RUNTIME_HIDDEN_CLIP) || canvas.checkVisibility?.() === false) {
webglDraws.add(canvas);
}
@@ -2230,7 +2232,9 @@
const draw = proto[method];
if (typeof draw !== "function") continue;
proto[method] = function (...args) {
if (!window[drawGate]?.skip) window.__hyperframesRecordWebglDraw(this.canvas);
try {
if (!window[drawGate]?.skip) window.__hyperframesRecordWebglDraw(this.canvas);
} catch {}
return draw.apply(this, args);
};
}
@@ -2239,6 +2243,7 @@
function inactiveWebglIssues(root, time) {
const drawn = [...webglDraws].filter((canvas) => canvas?.isConnected);
webglDraws.clear();
judgedThisSample = new WeakSet();
return drawn.map((canvas) => {
const scene =
canvas.closest("[data-composition-id]:not([data-width])") ??
@@ -1352,6 +1352,45 @@ describe("layout-audit.browser coordinate-frame findings", () => {
expect(runAudit().filter((i) => i.code === "webgl_draws_while_inactive")).toHaveLength(1);
expect(runAudit().some((issue) => issue.code === "webgl_draws_while_inactive")).toBe(false);
});
function installFakeWebgl(): { drawn: unknown[]; context: { canvas: unknown } } {
const drawn: unknown[] = [];
class FakeContext {
canvas: unknown;
drawArrays(...args: unknown[]) {
drawn.push(args);
}
}
(window as unknown as Record<string, unknown>).WebGLRenderingContext = FakeContext;
return { drawn, context: new FakeContext() };
}
it("lets an OffscreenCanvas context draw, and reports nothing for it", () => {
const { drawn, context } = installFakeWebgl();
mountScenes(true);
context.canvas = { width: 64, height: 64 };
(context as unknown as { drawArrays(mode: number): void }).drawArrays(4);
expect(drawn).toEqual([[4]]);
expect(runAudit().some((issue) => issue.code === "webgl_draws_while_inactive")).toBe(false);
});
it("checks a canvas's visibility once per sample, however many draws it makes", () => {
const { context } = installFakeWebgl();
const canvas = mountScenes(false);
const closest = vi.spyOn(canvas, "closest");
context.canvas = canvas;
for (let i = 0; i < 50; i++)
(context as unknown as { drawArrays(mode: number): void }).drawArrays(4);
expect(closest).toHaveBeenCalledTimes(1);
runAudit();
closest.mockClear();
(context as unknown as { drawArrays(mode: number): void }).drawArrays(4);
expect(closest).toHaveBeenCalledTimes(1);
});
});
describe("canvas_content_at_edge", () => {