Skip to content

Conversation

privatestefans
Copy link
Contributor

Description of change
  • Text doesn’t update correctly when using WebGPU. This happens because a new texture is created everytime the text changed, and replacing the original texture that still being used for rendering. The new texture doesn't replace the original GPU texture view, and the batch bind doesn't seems refreshed for the new texture. Because of that, the old texture still got rendered although the text already updated.
  • BitmapText doesn't update correctly when it's not visible. This occurs because _didTextUpdate already set to false even it's haven't rendered yet. This can be resolved by removing the one inside validateRenderable function, since the addRenderable function also sets _didTextUpdate to false and it correctly render the text.
  • Playground with the bug: https://pixiplayground.com/#/edit/LbxZkSCezG5SKwQ2TGgEw
Pre-Merge Checklist
  • Tests and/or benchmarks are included
  • Lint process passed (npm run lint)
  • Tests passed (npm run test)

…me condition

- `Text` doesn’t update correctly when using WebGPU. This happens because a new texture is created on each text change, replacing the original texture that still being used for rendering. The original texture view isn’t detached -- `.createView()` isn’t called, and the batch bind isn’t refreshed for the new texture. Because of that, the old texture still got rendered even the text already updated.
- `BitmapText` doesn't update correctly when it's not visible. This occurs because `_didTextUpdate` already being set to `false` even it's haven't being rendered yet. This was resolved by removing the one inside `validateRenderable` function, since the `addRenderable` function also sets `_didTextUpdate` to false and it correctly render the text
Copy link

codesandbox-ci bot commented Jul 16, 2025

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit ab9eba0:

Sandbox Source
pixi.js-sandbox Configuration

@Zyie Zyie requested a review from GoodBoyDigital July 16, 2025 13:05
@AndreMicheletti
Copy link

Hi, thanks for the PR @privatestefans ! Hope this gets shipped soon

@@ -70,6 +70,10 @@ export class GpuTextureSystem implements System, CanvasGenerator

public initSource(source: TextureSource): GPUTexture
{
let gpuTexture = this._gpuSources[source.uid];
Copy link
Member

@GoodBoyDigital GoodBoyDigital Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heyhey! whilst this is a fixe, the deeper issue is that initSource should not be called if the texture already exists. would love for us to understand why this is being called each time

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup I understand :3

when the text updates, the _updateGpuText line 41 got called, and then triggering a call to getTexture function on line 66.

public addRenderable(text: Text, instructionSet: InstructionSet)
{
const batchableText = this._getGpuText(text);
if (text._didTextUpdate)
{
this._updateGpuText(text);
text._didTextUpdate = false;
}
this._renderer.renderPipes.batch.addToBatch(batchableText, instructionSet);
}
public updateRenderable(text: Text)
{
const batchableText = this._getGpuText(text);
batchableText._batcher.updateElement(batchableText);
}
private _updateGpuText(text: Text)
{
const batchableText = this._getGpuText(text);
if (batchableText.texture)
{
this._renderer.canvasText.returnTexture(batchableText.texture);
}
text._resolution = text._autoResolution ? this._renderer.resolution : text.resolution;
batchableText.texture = batchableText.texture = this._renderer.canvasText.getTexture(text);
updateTextBounds(batchableText, text);
}


inside the getTexture function, a new texture is created from the updated text, and initSource function is triggered on line 125 for the new text.

const texture = getPo2TextureFromSource(canvasAndContext.canvas, frame.width, frame.height, resolution);
if (textureStyle) texture.source.style = textureStyle as TextureStyle;
if (style.trim)
{
// reapply the padding to the frame
frame.pad(style.padding);
texture.frame.copyFrom(frame);
texture.updateUvs();
}
if (style.filters)
{
// apply the filters to the texture if required..
// this returns a new texture with the filters applied
const filteredTexture = this._applyFilters(texture, style.filters);
// return the original texture to the pool so we can reuse the next frame
this.returnTexture(texture);
CanvasTextGenerator.returnCanvasAndContext(canvasAndContext);
// return the new texture with the filters applied
return filteredTexture;
}
this._renderer.texture.initSource(texture._source);
CanvasTextGenerator.returnCanvasAndContext(canvasAndContext);
return texture;

Copy link
Member

@GoodBoyDigital GoodBoyDigital left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

appreciate the proposed fix @privatestefans! I would like us to figure out why initSource is being called if the texture is already ready.

Sorry to be a pain :P

@privatestefans
Copy link
Contributor Author

privatestefans commented Jul 18, 2025

no worries, I also understand it should not be called every time the text updates. but after digging to the source code, I feel the FPS still drop significantly when we update many text. while this fix improve from 4 FPS to 12FPS, I feel it's better to have cache system for Text -- and I just found having back the cache system like #11505 would actually fix the performance for Text.

btw feel free to modify or close this PR in case if #11505 is preferred, I hope you can find something useful here to accelerate the fix anyway :D

@privatestefans
Copy link
Contributor Author

privatestefans commented Jul 18, 2025

The initSource for WebGL seems like simply bind the new texture tho:

public initSource(source: TextureSource)
{
this.bind(source);
}

But for WebGPU it replaced the GPU Texture in _gpuSources that still being used for rendering the text and causing the bug where the new text not rendered after being updated.

const gpuTexture = this._gpu.device.createTexture(textureDescriptor);
this._gpuSources[source.uid] = gpuTexture;

@GoodBoyDigital
Copy link
Member

thanks for the context @privatestefans ! this is all super helpful.

Copy link
Member

@GoodBoyDigital GoodBoyDigital left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good! I pushed a tiny tweak to bring it inline with the GLTextureSystem. Thanks for this fix!

Copy link

pkg-pr-new bot commented Jul 23, 2025

pixi.js-basepixi.js-bunny-mark

npm i https://pkg.pr.new/pixijs/pixijs/pixi.js@11547

commit: 0b05c79

@Zyie Zyie added the ✅ Ready To Merge Helpful when issues are in the queue waiting to get merged. This means the PR is completed and has t label Jul 23, 2025
@Zyie Zyie added this pull request to the merge queue Jul 23, 2025
Merged via the queue into pixijs:dev with commit 89230ba Jul 23, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✅ Ready To Merge Helpful when issues are in the queue waiting to get merged. This means the PR is completed and has t
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug: v8.10.1 -> Text stopping updates while using WebGPU renderer Bug: BitmapText not update while being invisible.
5 participants