glBlitFramebuffer generates GL_INVALID_OPERATION

In my application I render to a texture attached to the framebuffer object. Then a framebuffer attachment is blitted to the screen. Here are relevant parts of the code:

//initialization

glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);

glGenTextures(1, &fboTexId);
glBindTexture(GL_TEXTURE_2D, fboTexId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTexId, 0);

GLuint rboDepth;
glGenRenderbuffers(1, &rboDepth);
glBindRenderbuffer(GL_RENDERBUFFER, rboDepth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth);

GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

if (status != GL_FRAMEBUFFER_COMPLETE)
{
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    return false;
}

glBindFramebuffer(GL_FRAMEBUFFER, 0);


//render loop

glViewport(0, 0, w, h);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glBindFramebuffer(GL_FRAMEBUFFER, fboId);

glViewport(0, 0, w, h);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

render();

int sample_buffers = 0;
glGetFramebufferParameteriv(GL_FRAMEBUFFER, GL_SAMPLE_BUFFERS, &sample_buffers);

glBindFramebuffer(GL_FRAMEBUFFER, 0);

sample_buffers = 0;
glGetFramebufferParameteriv(GL_FRAMEBUFFER, GL_SAMPLE_BUFFERS, &sample_buffers);

glBindFramebuffer(GL_READ_FRAMEBUFFER, fboId);
glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR);

The above code works fine but when change a destination rectangle, for example:

glBlitFramebuffer(0, 0, w, h, 0, 0, w / 2, h / 2, GL_COLOR_BUFFER_BIT, GL_LINEAR);

I get OpenGL error 1282 - GL_INVALID_OPERATION. The message from the debug context looks like this:

Error has been generated. GL error GL_INVALID_OPERATION in BlitFramebuffer: (ID: 3482180659) Generic error

Documentation says:

GL_INVALID_OPERATION is generated if the value of GL_SAMPLE_BUFFERS for either read or draw buffers is greater than zero and the dimensions of the source and destination rectangles is not identical.

but sample buffers for the generated framebuffer and default framebuffer equals 0. Why do I get GL_INVALID_OPERATION ? Changing glBlitFramebuffer filter to GL_NEAREST doesn’t help.

I think you forgot to glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)

glBindFramebuffer(GL_FRAMEBUFFER, 0) should be sufficient but even after adding glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0) I still get GL_INVALID_OPERATION.

there is a numerous number of reasons that this could be happening and its not very clear what’s wrong from your code but make sure to check all the reasons, if you go to this website glBlitFramebuffer - OpenGL 4 Reference Pages scroll to errors make sure you have gone through and verified them in your code.

I have made a mistake during debugging. GL_INVALID_OPERATION has been generated because a default framebuffer has multiple samples in contrast to a generated framebuffer. When I turn off multisampling for a default framebuffer everything works fine.

1 Like

You can solve this by doing 2 blits:

  • 1 for downsampling (MSAA->1X, size1 → size1)
  • 1 for rescaling (size1 → size2)

Alternatively, use one of the blit fitlers added in:

which allow you to downsample+rescale in 1 single Blit call.

Also, if the uesr is overriding the window creation to force some degree of MSAA (multisample buffer allocation), tell them to stop it and flip that off. Blitting between two different MSAA configurations is going to trigger this issue to IIRC. You want an MSAA offscreen FBO and a 1x window. Otherwise, you end up having to do stupid, ineffficient things like having 2 offscreen FBOs (MSAA and 1x) and then doing 2 blits instead of 1 (or 3 blits instead of 2) to avoid the error caused by the user forcing MSAA allocation on the window.