3
votes

I have a webgl project setup that uses 2 pass rendering to create effects on a texture.

Everything was working until recently chrome started throwing this error:

[.WebGL-0000020DB7FB7E40] GL_INVALID_OPERATION: Feedback loop formed between Framebuffer and active Texture. 

This just started happening even though I didn't change my code, so I'm guessing a new update caused this.

I found this answer on SO, stating the error "happens any time you read from a texture which is currently attached to the framebuffer".

However I've combed through my code 100 times and I don't believe I am doing that. So here is how I have things setup.

Create a fragment shader with a uniform sampler.

uniform sampler2D sampler;

Create 2 textures

var texture0 = initTexture(); // This function does all the work to create a texture 
var texture1 = initTexture(); // This function does all the work to create a texture 

Create a Frame Buffer

var frameBuffer = gl.createFramebuffer();

Then I start the "2 pass processing" by uploading a html image to texture0, and binding texture0 to the sampler.

I then bind the frame buffer & call drawArrays:

gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture1, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

To clean up I unbind the frame buffer:

gl.bindFramebuffer(gl.FRAMEBUFFER, null);

Edit:

After adding break points to my code I found that the error is not actually thrown until I bind the null frame buffer. So the drawArrays call isn't causing the error, it's binding the null frame buffer afterwards that sets it off.

1
You need to show more code but the code you posted as is likely has a feedback loop. The last texture you created was texture1 so it's still bound. The attach it to framebuffer. You then draw. If your shader uses textures it certainly looks like it's trying to read from texture1 and write from texture1 at the same time. - gman
Maybe I'm misunderstanding how this works, but can't my shader only read a texture from the sampler. So with texture0 bound to the sampler how could I be reading from texture1 at all? I know texture1 is still the active texture, I thought it had to be to bind it to the frame buffer. Should I make it "non active" after binding it? - YAHsaves
@gman, also please see my edit. Not sure why, but it seems that binding the null frame buffer after the draw call is what causes the error. - YAHsaves
I am pretty sure that this is actually caused by broken libANGLE implementation of bound sampler tracking. Once a texture is bound as a sampler, even if it's unbound right after, the browser thinks it's being used. That change was implemented in this commit, and there were a few more fixes; it seems to be working in the most recent Canary. - Bartek Banachewicz
voting to close. You haven't put a mininal-reproducable-example. Please add one - gman

1 Answers

2
votes

Chrome since version 83 started to perform conservative checks for the framebuffer and the active texture feedback loop. These checks are likely too conservative and affect usage that should actually be allowed.

In these new checks Chrome seem to disallow a render target to be bound to any texture slot, even if this slot is not used by the program.

In your 2 pass rendering you likely have something like:

  1. Initialize a render target and create a texture that points to a framebuffer.
  2. Render to the target.

In 1 you likely bind a texture using gl.bindTexture(gl.TEXTURE_2D, yourTexture) you need to then, before the step 2, unbind the texture using gl.bindTexture(gl.TEXTURE_2D, null); Otherwise Chrome will fail because the render target is bound as a texture, even though this texture is not sampled by the program.