Skip to content

DynamicTexture constructor leaks a WebGL texture on every create/destroy cycle (4.2.1) #7379

Description

@rmartone

Version

  • Phaser Version: 4.2.1
  • Operating system: MAC OSX (latest)
  • Browser: Chrome (latest)

Description

In WebGL mode, creating and removing a DynamicTexture leaves one WebGL texture wrapper retained in
renderer.glTextureWrappers.

The DynamicTexture constructor allocates a texture through the base Texture/TextureSource constructor, then replaces
frame.source.glTexture with this.drawingContext.texture without disposing the original wrapper.

Removing the DynamicTexture destroys the replacement, but the original remains registered with the renderer. In an
isolated reproduction, the original WebGL texture also remains valid according to gl.isTexture().

Expected: after each create/remove cycle, the wrapper count returns to its baseline.

Actual: the retained wrapper count increases by one per cycle.

Example Test Code

Run against unpatched Phaser 4.2.1:

<!doctype html>
<html>
<body>
<script src="https://cdn.jsdelivr.net/npm/phaser@4.2.1/dist/phaser.js"></script>
<script>
new Phaser.Game({
    type: Phaser.WEBGL,
    width: 64,
    height: 64,
    audio: { noAudio: true },
    scene: {
        create: function () {
            const renderer = this.game.renderer;
            const baseline = renderer.glTextureWrappers.length;

            for (let i = 0; i < 4; i++) {
                const key = `texture-leak-${i}`;
                this.textures.addDynamicTexture(key, 8, 8);
                this.textures.remove(key);

                console.log(
                    `Cycle ${i + 1}: retained wrappers =`,
                    renderer.glTextureWrappers.length - baseline
                );
            }
        }
    }
});
</script>
</body>
</html>

Expected counts: 0, 0, 0, 0.
Actual counts: 1, 2, 3, 4.

Additional Information

Disposing the original texture before replacing it in the DynamicTexture constructor eliminates the growth in the
isolated reproduction:

if (!isCanvas)
{
    var frame = this.get();
    renderer.deleteTexture(frame.source.glTexture);
    frame.source.glTexture = this.drawingContext.texture;
}

Related history: #6669 reports a DynamicTexture create/destroy memory leak in Phaser 3.70. This report concerns the
DrawingContext replacement path in 4.2.1; I have not established whether it shares the same underlying cause.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions