Использование twgl и кадровых буферов приводит к утечке памяти в графическом процессоре и приводит к сбою браузера (прилагается plunkr) - PullRequest
0 голосов
/ 14 мая 2019

Я пишу приложение гистограммы в webgl, используя библиотеку twgl.js. Я успешно реализовал это. Но он очень легко вылетает из браузера.

Я добавил планкр здесь @ https://plnkr.co/edit/hK9YXyT0Cj9BEUowYiKVSubH?p=info.

В основном часть рендеринга находится в renderer.js.

Пожалуйста, найдите jpeg с вашего локального компьютера и контролируйте память Chrome GPU, используя SHIFT + ESC после включения памяти GPU. После того, как изображение загружено, оно вычислит гистограмму для этой области на изображении и само увеличит / уменьшит масштаб, и память увеличивается с каждым увеличением.

Проблема в том, что он вылетает из GPU только с одним изображением. Чтобы быстрее решить проблему, я добавил setInterval, который вызывается каждые 100 мсек, чтобы перерисовать изображение и вычислить гистограмму.

Код:

`

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
    }
});

// make a 256x1 RGBA floating point texture and attach to a framebuffer
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");
}

// Render sum of each color

// we're going to render a gl.POINT for each pixel in the source image
// That point will be positioned based on the color of the source image
// we're just going to render vec4(1,1,1,1). This blend function will
// mean each time we render to a specific point that point will get
// incremented by 1.
gl.blendFunc(gl.ONE, gl.ONE);
gl.enable(gl.BLEND);
gl.useProgram(histProgramInfo.program);

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

// render each channel separately since we can only position each POINT
// for one channel at a time.
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
// We're rendering are 256x1 pixel sum texture to a single 1x1 pixel texture

// make a 229x1 pixel RGBA, FLOAT texture attached to a framebuffer
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);
// render histogram.
//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 Ответ

1 голос
/ 14 мая 2019

Код выделяет несколько больших текстур каждый интервал, вызывая 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.Создаваемые им данные предназначены для использования в любом случае, когда ваше приложение должно использовать эти данные.Он не знает, разделяете ли вы вложения между кадровыми буферами (общие), поэтому он не может управлять ресурсами для вас.Это зависит от вас.

...