web-dev-qa-db-ja.com

使用後にWebGLキャンバスコンテキストをクリーンアップしてGPUからアンロードするにはどうすればよいですか?

WebGLコンテキストプログラムをクリーンアップし、プログラム、バッファ、およびすべてをGPUとdom要素からアンロードするにはどうすればよいですか?

ポイ捨てをしないようにしたいと思います。

また、可能であればキャンバスを再利用するとよいでしょう(そして、それが2dまたはwebglコンテキストであるかどうかはわかりません)。

12
Bartvds

Glコンテキスト、すべてのglオブジェクト、およびキャンバスへのすべての参照を失い、DOMからキャンバスを削除することができます。残念ながら、JavaScriptはガベージコレクションであるため、ブラウザが実際にいつメモリを解放するかはわかりません。これを正しく行うことをテストするためのいくつかの適合性テストがありますが、ただ希望して祈るだけではない場合は..。

作成したすべてのものでgl.deleteXXXを呼び出し、すべてのバインドポイントのバインドを解除して、すべてのリソースを解放します。つまり、すべてのテクスチャユニットについて、配列、フレームバッファ、レンダーバッファと同じように、nullを含むすべてのターゲットでgl.bindTextureを呼び出します。

var numTextureUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
for (var unit = 0; unit < numTextureUnits; ++unit) {
  gl.activeTexture(gl.TEXTURE0 + unit);
  gl.bindTexture(gl.TEXTURE_2D, null);
  gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
}
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);

// Delete all your resources
// Note!!!: You'd have to change this code to delete the resources YOU created.
gl.deleteTexture(someTexture);
gl.deleteTexture(someOtherTexture);
gl.deleteBuffer(someBuffer);
gl.deleteBuffer(someOtherBuffer);
gl.deleteRenderbuffer(someRenderbuffer);
gl.deleteFramebuffer(someFramebuffer);

Nullを属性にバインドすることはできないため、削除する前に、すべてのバッファーのサイズを1に設定できます(ゼロは許可されません)。それか、新しいバッファを作成して、すべての属性に割り当てます。

最初の例

// set a buffer to 1 byte before deleting
// NOTE: You'd need to do this for ALL BUFFERS you created.
gl.bindBuffer(gl.ARRAY_BUFFER, someArrayBuffer);
gl.bufferData(gl.ARRAY_BUFFER, 1, gl.STATIC_DRAW);
gl.deleteBuffer(someArrayBuffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, someElementArrayBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 1, gl.STATIC_DRAW);
gl.deleteBuffer(someElementArrayBuffer);

または、新しいバッファを作成して、すべての属性に割り当てます

var buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
var numAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
for (var attrib = 0; attrib < numAttributes; ++attrib) {
  gl.vertexAttribPointer(attrib, 1, gl.FLOAT, false, 0, 0);
}

これにより、古いバッファが属性からバインド解除されます。

最後に、キャンバスサイズを1x1ピクセルに設定します。

gl.canvas.width = 1;
gl.canvas.height = 1;

これは完璧なソリューションではありませんが、数kを除くすべてのメモリをすぐに解放し、制御不能なガベージコレクションを待つ必要はありません。

キャンバスを最初から再利用することはできません。キャンバスには、最初に要求したのと同じコンテキストが常にあります。

loseContextに関する@Johanの回答も参照してください。

20
gman

コンテキストを失うには、拡張子WEBGL_lose_contextを次のように使用します。

gl.getExtension('WEBGL_lose_context').loseContext();

https://developer.mozilla.org/en-US/docs/Web/API/WEBGL_lose_context/loseContext を参照してください。

7
Johan van Breda