PixiJS: PrepareUpload
by UlyssesZhan
HTML
<script type="importmap">
{
"imports": {
"pixi.js": "//cdn.jsdelivr.net/npm/[email protected]/dist/pixi.mjs"
}
}
</script>
JavaScript
import { Application, Container, Graphics, Text, extensions, PrepareSystem } from "pixi.js";
extensions.add(PrepareSystem);
(async () => {
const app = new Application();
await app.init();
// A normal text object.
const text = new Text({ text: 'race' });
// A masked Graphics causes Pixi to break the batch mid-render
const mask = new Graphics().rect(0, 0, 50, 50).fill(0xffffff);
const masked = new Graphics().circle(25, 25, 20).fill(0xff0000);
masked.mask = mask;
const stage = new Container();
// Text must be collected before the masked object so the undefined-texture
// batch element is present when StencilMaskPipe asks the batcher to break.
stage.addChild(text);
stage.addChild(mask);
stage.addChild(masked);
// 1. Queue the async prepare upload.
app.renderer.prepare.upload(text);
// 2. Render before the async prepare callback runs.
// This makes Text._didTextUpdate = false after a valid texture is created.
console.log('first render');
app.renderer.render(stage);
console.log('first render done');
// 3. Let PixiJS's Ticker.system run the queued prepare.upload().
// CanvasTextPipe.initGpuText() replaces the valid GPU data with a fresh
// BatchableText whose texture is undefined.
await new Promise((resolve) => setTimeout(resolve, 100));
// 4. Force Pixi to rebuild the render group. Without this, the second render
// can reuse the first render's already-built instructions, which still point
// to the old valid GPU batchable. Adding/removing a child makes
// structureDidChange true, so Pixi rebuilds the instruction set and now
// picks up the fresh BatchableText that has texture === undefined.
stage.addChild(new Container());
// 5. Render again. Because _didTextUpdate is already false, CanvasTextPipe
// does not regenerate the texture, and the undefined-texture batchable is
// sent to the batcher. The next batch break throws the CI error.
console.log('second...