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...