如何在使用后从GPU清理和卸载WebGL画布上下文?

Bar*_*vds 11 javascript canvas webgl

如何清理WebGL上下文程序并从GPU和dom-element卸载程序,缓冲区和所有内容?

我想确保我们不乱扔垃圾.

此外,它会是很好,如果可以重新使用画布(我不知道这是否会是2dwebgl上下文).

gma*_*man 21

您可以丢失对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);
Run Code Online (Sandbox Code Playgroud)

因为您无法将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);
Run Code Online (Sandbox Code Playgroud)

或者创建一个新缓冲区并将其分配给所有属性

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);
}
Run Code Online (Sandbox Code Playgroud)

这将从属性中解除旧缓冲区的绑定.

最后将画布大小设置为1x1像素.

gl.canvas.width = 1;
gl.canvas.height = 1;
Run Code Online (Sandbox Code Playgroud)

它不是一个完美的解决方案,但它会立即释放除了几k内存之外的所有内存,而不是等待你无法控制的垃圾收集.

至于从头开始重用画布你不能.画布将始终具有您首次要求的相同上下文.

另见@ Johan的回答 loseContext


Joh*_*eda 7

要丢失上下文,请使用扩展名WEBGL_lose_context作为

gl.getExtension('WEBGL_lose_context').loseContext();
Run Code Online (Sandbox Code Playgroud)

请参阅https://developer.mozilla.org/en-US/docs/Web/API/WEBGL_lose_context/loseContext

  • 感谢您的澄清! (4认同)
  • 你链接到`restoreContext()`而不是[`loseContext()`](https://developer.mozilla.org/en-US/docs/Web/API/WEBGL_lose_context/loseContext).此外,前两行表明这不符合您的要求:*"WEBGL_lose_context.loseContext()方法是WebGL API的一部分,允许您****模拟****丢失WebGLRenderingContext上下文的上下文它触发了WebGL规范中描述的用于处理上下文丢失的步骤.****在调用WEBGL_lose_context.restoreContext()之前,上下文将一直丢失."*** (3认同)
  • @Job规范不是代码,它可以被含糊地解释.但是,还有以下内容:_Implementations应该在调用此方法时销毁底层图形上下文和所有图形资源.**这是应用程序以编程方式停止使用WebGL API的推荐机制.**_关于单词_simulate_ - 我猜它是因为_This扩展公开了模拟丢失和恢复WebGL上下文的新函数,**甚至在上下文永远不会丢失的平台上** - 即在不可能进行破坏时进行模拟 (3认同)