Keep a recording behind another tab from dropping its frames
feuerwerk / gate (push) Successful in 4m52s
feuerwerk / suite (push) Successful in 19m5s

In CI run 699 check 68k (real time behind a tab) got 21 of 120 frames.
The beat ticked 100 times, but 83 frames were dropped as busy. Late in
a long browser session the GPU behind a hidden tab took up to 1.5 s to
finish a read back, so all three read-back buffers were still on their
way when the next frame was due. Locally on melektaus-atx this showed
only in the full run of modules 01 to 68, and not in every one.

- The render loop no longer draws the screen while the page is hidden.
  Nobody sees it there, and the drawing was competing with the read
  backs for the slow GPU.
- A recording of the editor copies the canvas, so it turns the drawing
  back on with `drawWhileHidden` while it runs.
- `PictureReader.collect` reads the oldest buffer at once when the page
  is hidden and no buffer is free, instead of dropping the frame. The
  main thread waits for the GPU there, which nobody sees either.
- More buffers are no fix: with 30 of them the frames piled up at the
  encoder instead (45 frames, 56 dropped).

Tests:
- render.test.ts: 18/18, the new test is red without the hidden check
- Full run of modules 01 to 68 on melektaus-atx with a counting probe:
  read at once only 18 frames, 63 dropped; both parts 106 frames,
  2 dropped
- e2e 67 and 68 on melektaus-atx without probe: 68k green, 97 frames,
  0 dropped. Red there only "a clip that starts later", the known
  timing wobble from task 697
- Gate on melektaus-atx: CHECK EXIT 0, 313 files, 4841 tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-15 08:02:08 +02:00
1 parent 406839baea
commit 2f13f9a0b9
5 files changed
+53 -2

No files matched your search

+27
View File
@@ -3,6 +3,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import {
afterFrames,
cancelFrameWork,
drawWhileHidden,
initRenderLoop,
isRendering,
onFrame,
@@ -196,6 +197,32 @@ describe('render loop', () => {
expect(ran).toBe(10);
});
it('draws nothing behind another tab, unless a recording of the editor needs the canvas', () => {
const { app, tick } = fakeApp();
initRenderLoop(app as unknown as Application);
const page = { hidden: true };
vi.stubGlobal('document', page);
try {
let ran = 0;
onFrame('drag', () => (ran += 1));
tick();
expect(ran).toBe(1);
expect(app.drawn).toBe(0);
expect(renderCount()).toBe(0);
drawWhileHidden(true);
tick();
expect(app.drawn).toBe(1);
drawWhileHidden(false);
page.hidden = false;
tick();
expect(app.drawn).toBe(2);
} finally {
vi.unstubAllGlobals();
}
});
it('afterFrames gives up rather than hanging when no frame ever comes', async () => {
vi.useFakeTimers();
try {