CoderAnswer - 程序员编程问答

使用twgl和framebuffers会导致GPU内存泄漏并导致浏览器崩溃(附带plunkr)

by @subhfyu546754

opengl-es webgl twgl.js

我正在使用twgl.js库在webgl中编写直方图应用程序。 我已经成功实现了它。但它很容易崩溃浏览器。

我在这里添加了plunkr @ https://plnkr.co/edit/hK9YXyT0Cj9BEUowYiKV?p=info。

渲染部分主要在renderer.js中。

请在本地计算机上浏览jpeg,并在启用GPU内存后使用SHIFT + ESC监控chrome GPU内存。 加载图像后,它将计算图像中该区域的直方图,并自动缩小/缩小,每次缩放都会增加内存。

问题是它只能用单个图像崩溃GPU。 为了更快地解决问题,我添加了一个setInterval,每100ms调用一次,以重新渲染图像并计算直方图。

代码:

`

var prepareHistogram = function (img) {
//arrays.texcoord = [0.2, 0.2, 1.0, 0.2, 0.2, 1.0, 1.0, 1.0];
gl.arrays = arrays;
gl.arrays.position.data = [-1, -1, 1, -1, -1, 1, 1, 1];
gl.arrays.position.numComponents = 2;
gl.arrays.texcoord.numComponents = 2;
//gl.arrays.texcoord = [0.2, 0.2, 1.0, 0.2, 0.2, 1.0, 1.0, 1.0];

quadBufferInfo = twgl.createBufferInfoFromArrays(gl, gl.arrays);
//quadBufferInfo = twgl.primitives.createXYQuadBufferInfo(gl);
quadBufferInfo.indices = null;

var newFbi = twgl.createFramebufferInfo(gl);
twgl.bindFramebufferInfo(gl, newFbi);

gl.useProgram(newProgramInfo.program);
twgl.setBuffersAndAttributes(gl, newProgramInfo, quadBufferInfo);
twgl.setUniforms(newProgramInfo, {
    u_texture: texture,
    u_resolution: [img.width, img.height]
});
twgl.drawBufferInfo(gl, gl.TRIANGLES, quadBufferInfo);
 /* twgl.bindFramebufferInfo(gl,null);
twgl.drawBufferInfo(gl, gl.TRIANGLES, quadBufferInfo);

return;   */

numIds = img.width * img.height;
pixelIds = dummyPixelIds.subarray(0, numIds);
var pixelIdBufferInfo = twgl.createBufferInfoFromArrays(gl, {
    pixelId: {
    size: 2,
    data: pixelIds,
    numComponents : 1
    }
});

//制作256x1 RGBA浮点纹理并附加到帧缓冲区
var sumFbi = twgl.createFramebufferInfo(gl, [{
    type: gl.FLOAT,
    min: gl.NEAREST,
    mag: gl.NEAREST,
    wrap: gl.CLAMP_TO_EDGE,
}, ], 256, 1);

if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
    alert("can't render to floating point texture");
}

//渲染每种颜色的总和

//我们将为源图像中的每个像素渲染一个gl.POINT
//该点将根据源图像的颜色进行定位
//我们要渲染vec4(1,1,1,1)。这种混合功能会
//表示每次渲染到该点将获得的特定点
//递增1。
gl.blendFunc(gl.ONE, gl.ONE);
gl.enable(gl.BLEND);
gl.useProgram(histProgramInfo.program);

twgl.setBuffersAndAttributes(gl, histProgramInfo, pixelIdBufferInfo);
twgl.bindFramebufferInfo(gl, sumFbi);

//分别渲染每个通道,因为我们只能定位每个POINT
//一次一个频道。
gl.colorMask(true, true, true, false);
twgl.setUniforms(histProgramInfo, {  
    u_texture: newFbi.attachments[0],  
    u_resolution: [img.width, img.height]
});
twgl.drawBufferInfo(gl, gl.POINTS, pixelIdBufferInfo);

gl.colorMask(true, true, true, true);
gl.blendFunc(gl.ONE, gl.ZERO);
gl.disable(gl.BLEND);

//render-compute min
//我们渲染的是单个1x1像素纹理的256x1像素和纹理

//将一个229x1像素的RGBA,FLOAT纹理附加到帧缓冲区
var maxFbi = twgl.createFramebufferInfo(gl, [{
    type: gl.FLOAT,
    min: gl.NEAREST,
    mag: gl.NEAREST,
    wrap: gl.CLAMP_TO_EDGE,
}, ], 229, 1);

twgl.bindFramebufferInfo(gl, maxFbi);

gl.useProgram(maxProgramInfo.program);
twgl.setBuffersAndAttributes(gl, maxProgramInfo, quadBufferInfo);
twgl.setUniforms(maxProgramInfo, {
    u_texture: sumFbi.attachments[0],
    pixelCount : pixelCount
});
twgl.drawBufferInfo(gl, gl.TRIANGLES, quadBufferInfo);
//渲染直方图。
//twgl.bindFramebufferInfo(gl,null);
var newFbi2 = twgl.createFramebufferInfo(gl);
twgl.bindFramebufferInfo(gl, newFbi2);

gl.useProgram(showProgramInfo.program);
twgl.setBuffersAndAttributes(gl, showProgramInfo, quadBufferInfo);
twgl.setUniforms(showProgramInfo, {
    u_resolution: [img.width, img.height],
    u_res: [img.width, img.height],
    u_maxTexture: maxFbi.attachments[0],
    inputImage : newFbi.attachments[0]
});
twgl.drawBufferInfo(gl, gl.TRIANGLES, quadBufferInfo);

twgl.bindFramebufferInfo(gl,null);

gl.useProgram(showProgramInfo2.program);

twgl.setUniforms(showProgramInfo2, {
    u_texture: newFbi2.attachments[0],
    u_resolution:  [gl.canvas.width, gl.canvas.height]
});

//arrays.texcoord.numComponents = 2;
//arrays.position.data = [ar.x1, ar.y1, ar.x2, ar.y1, ar.x1, ar.y2, ar.x2, ar.y2];
//gl.arrays = arrays;
//quadBufferInfo = twgl.primitives.createXYQuadBufferInfo(gl);

//gl.arrays = arrays;

gl.arrays.position.data = [ar.x1, ar.y1, ar.x2, ar.y1, ar.x1, ar.y2, ar.x2, ar.y2];
//gl.arrays.texcoord = [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0];
/* gl.arrays.texcoord = [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0];
gl.arrays.texcoord.numComponents = 2;
gl.arrays.position.numComponents = 2; */

quadBufferInfo = twgl.createBufferInfoFromArrays(gl, gl.arrays);

quadBufferInfo.indices = null;
twgl.setBuffersAndAttributes(gl, showProgramInfo2, quadBufferInfo);
twgl.drawBufferInfo(gl, gl.TRIANGLES, quadBufferInfo);

}
`


1个答案

0 by @gman

代码通过调用twgl.createFramebufferInfo在每个时间间隔分配多个大纹理,因此代码最终会耗尽内存。

如果可能的话,你应该在初始时分配你的纹理。换句话说,在初始化时调用twgl.createFrameBufferInfo,如果你需要它们不同的大小,请稍后调用twgl.resizeFramebufferInfo来改变它们的大小。

否则你可以取消分配它们

function freeFramebufferInfoResources(gl,fbi){
  for (const attachment of fbi.attachments) {
    if (attachment instanceof WebGLTexture) {
      gl.deleteTexture(attachment);
    } else {
      gl.deleteRenderbuffer(attachment);
    }
  }
  gl.deleteFramebuffer(fbi.framebuffer);
}

至于为什么twgl不包含这个函数,因为twgl只是WebGL的帮助器。无论如何,您创建的数据都可以用于您的应用程序需要使用该数据。它不知道您是否跨帧缓冲区(通用)共享附件,因此无法为您管理资源。随你(由你决定。


相关问题