Shader.preDestroy leaks its ShaderQuad's vertex buffer and VAO on every create/destroy cycle (4.2.1)
I maintainer di solito rispondono entro 2 giorni
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 86/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- javascript
- Ambito
- game-dev
Direzione di ricerca
Parti da preDestroy nel sorgente del game object Shader (src/gameobjects/Shader/Shader.js) e traccia renderNode fino allo ShaderQuad, al suo WebGLVertexBufferLayoutWrapper e al ProgramManager. Leggi come WebGLRenderer registra e rilascia i wrapper (glBufferWrappers, glVAOWrappers, deleteBuffer) per rispecchiare quel pattern per i VAO, eventualmente aggiungendo un deleteVAO. L'issue è risolta quando la sonda HTML dell'issue stampa 0, 0, 0, 0 per entrambi i contatori, incluso il caso di distruzione prima del primo disegno, senza liberare il programma condiviso né genericQuadIndexBuffer.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
In WebGL mode, every Shader game object builds its own ShaderQuad render node. The node allocates a vertex buffer
(WebGLVertexBufferLayoutWrapper → renderer.createVertexBuffer, registered in renderer.glBufferWrappers).
On first draw, its ProgramManager creates a VAO per linked program
(renderer.createVAO, registered in renderer.glVAOWrappers).
Shader.preDestroy only nulls this.renderNode. Neither the vertex buffer nor the VAO is released, so both stay registered with the renderer, and their GL objects stay allocated, for the life of the game.
This adds up quickly when shaders are created and destroyed repeatedly. For example, a UI button that draws its background with a Shader and lives in an overlay that is rebuilt on every show leaks one buffer and one VAO per button per show.
Expected: after each create/draw/destroy cycle, the buffer and VAO wrapper counts return to their baseline.
Actual: both counts grow by one per cycle. A shader destroyed before its first draw still leaks its vertex buffer.
Example Test Code
Run against unpatched Phaser 4.2.1:
<!doctype html>
<html>
<body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>
<script>
const config = {
name: 'LeakProbe',
fragmentSource: `
precision mediump float;
varying vec2 outTexCoord;
void main() { gl_FragColor = vec4(outTexCoord, 0.0, 1.0); }
`
};
new Phaser.Game({
type: Phaser.WEBGL,
width: 128,
height: 128,
audio: { noAudio: true },
scene: {
create: function () {
const renderer = this.game.renderer;
let baseBuffers = null;
let baseVAOs = null;
let shader = null;
let cycle = 0;
// Each cycle: create a Shader, let it draw once (which creates its VAO), then destroy it.
this.game.events.on('postrender', () => {
if (baseBuffers === null) {
baseBuffers = renderer.glBufferWrappers.length;
baseVAOs = renderer.glVAOWrappers.length;
} else if (shader) {
shader.destroy();
shader = null;
cycle++;
console.log(
`Cycle ${cycle}: retained buffers = ${renderer.glBufferWrappers.length - baseBuffers},`,
`retained VAOs = ${renderer.glVAOWrappers.length - baseVAOs}`
);
}
if (cycle < 4) {
shader = this.add.existing(new Phaser.GameObjects.Shader(this, config, 64, 64, 64, 64));
}
});
}
}
});
</script>
</body>
</html>
Expected counts: 0, 0, 0, 0 for both.
Actual counts: 1, 2, 3, 4 for both.
Additional Information
Releasing the render node's own resources in Shader.preDestroy eliminates the growth:
preDestroy: function ()
{
var renderNode = this.renderNode;
if (renderNode)
{
// Release this Shader's own GL resources. The program and the
// index buffer are shared, so they stay.
var renderer = renderNode.renderer;
var programs = renderNode.programManager.programs;
for (var key in programs)
{
var vao = programs[key].vao;
var vaoIndex = renderer.glVAOWrappers.indexOf(vao);
if (vaoIndex !== -1)
{
renderer.glVAOWrappers.splice(vaoIndex, 1);
}
vao.destroy();
}
renderer.deleteBuffer(renderNode.vertexBufferLayout.buffer);
}
this.renderNode = null;
// ... existing preDestroy body unchanged
}
The shader program is shared through ShaderProgramFactory's key cache, and the index buffer is the renderer's shared genericQuadIndexBuffer, so neither should be deleted here. WebGLRenderer has no VAO counterpart to deleteBuffer, which is why the fix removes the VAO from glVAOWrappers directly. A deleteVAO method on the renderer might be the cleaner upstream shape.
The same leak affects any ShaderQuad-based object that is destroyed; Shader is just the most direct way to reproduce it. The master branch's Shader.preDestroy is unchanged from 4.2.1.
- Lingua principale
- JavaScript
- Stelle
- 40.4k
- Fork
- 7.2k
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di phaserjs/phaser
-
Type definition for TilemapLayer.getTileAt is wrongForse già presa @hkbughk l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
I maintainer di solito rispondono entro 2 giorni
-
Black opaque background on transparent Phaser.Text textures in Phaser 4.2.1 on older iOS WebGLAperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 85/100
I maintainer di solito rispondono entro 2 giorni
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
I maintainer di solito rispondono entro 2 giorni
-
WebGL stroke of a Polygon drops a vertex when its origin-shifted position equals the previous raw vertexForse già presa @ICOM725 l’ha presa 37 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
phaserjs/phaser#7361 · 1 commento ·
I maintainer di solito rispondono entro 2 giorni
-
MouseManager.stopListeners never removes the wheel listener — destroyed Game stays retained through the canvasForse già presa @schulerj89 l’ha presa 77 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 2 giorni
Tutte le issue di phaserjs/phaser
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
-
enhancement
Difficoltà 1/5 1-3 ore Idoneità per principianti 85/100
holepunchto/hrpc-test#28 ·
-
good first issue
Difficoltà 1/5 1-3 ore Idoneità per principianti 88/100
anoopcodehack/DevBoard#616 ·
I maintainer di solito rispondono entro 2 giorni
-
idnits3
Difficoltà 2/5 1-3 ore Idoneità per principianti 63/100
ietf-tools/idnits#319 ·
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 76/100
521xueweihan/HelloGitHub#3939 ·