glBlitFramebuffer Invalid Operation
Asked Answered
V

1

6

I've been messing around with framebuffers and render to texture and I came across the need to blit them. Again on some machines I get a GL_INVALID_OPERATION right after the glBlitFramebuffer call. Each texture bound to the framebuffer is setup the exact same way, all the same size and parameters. Also, when I try to blit one entire texture (previously succesfully rendered to) to another framebuffer, only the destination 'rectangle' to write in is smaller than the rectangle to read from (e.g. when I want to blit it to a quarter of the screen), it throws a GL_INVALID_OPERATION too.

EDIT: Actually it always throws the error whenever the rectangles to read from and draw to have a different size, so I can't blit to a texture of a different size, or the same size but a different sized 'render to' area...?

Everytime I blit to a manually generated framebuffer the status is checked through glCheckFramebufferStatus and it always returns GL_FRAMEBUFFER_COMPLETE.

-BIGGEST SNIP EVER-, see below for shorter 'source code', obviously a couple C++ errors and not complete, but its only for the GL calls

The OpenGL error occurs when I call the last method of the viewport (Viewport::blit) with the screen framebuffer as target (by passing NULL). It first sets the read buffer of its own framebuffer (the draw buffers were already set) and then it calls RenderTarget::blit which calls glBlitFramebuffer. In the blit method it binds both buffers, and you can see it calls glCheckFramebufferStatus there which does not return an error.

I've been reading this over and over but I can't seem to find the error that causes it. When I blit the color buffer I use GL_LINEAR, otherwise I use GL_NEAREST All color buffers use GL_RGB32F as internal format and the depth buffer (which I never blit) uses GL_DEPTH_COMPONENT32F

EDIT, a shorter example, just took all the GL calls and filled the params I used

glBindFramebuffer(GL_READ_FRAMEBUFFER, _GL_Framebuffer);
glReadBuffer(GL_COLOR_ATTACHMENT0 + index);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);

// OpenGL error check, does not return an error

glBindFramebuffer(GL_READ_FRAMEBUFFER, _GL_Framebuffer);
GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
{
    // Some error checking, fortunately status always turns out to be complete
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

glBlitFramebuffer(0, 0, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight, target, (target == GL_COLOR_BUFFER_BIT) ? GL_LINEAR : GL_NEAREST);

// If the source/destination read/draw rectangles are different in size, GL_INVALID_OPERATION is cought here

And the Framebuffer/Texture creation:

glGenFramebuffer(1, &_GL_Framebuffer);

glGenTextures(1, &_GL_ZBuffer);
glBindTexture(GL_TEXTURE_2D, _GL_ZBuffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, screenWidth, screenHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);

glBindFramebuffer(GL_FRAMEBUFFER, _GL_Framebuffer);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT + 0, _GL_ZBuffer, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

int writeIndices[BUFFER_COUNT];
for(unsigned int i = 0; i < BUFFER_COUNT; ++i)
{
    writeIndices[i] = i;

    glGenTextures(1, &_GL_Texture);
    glBindTexture(GL_TEXTURE_2D, _GL_Texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, screenWidth, screenHeight, 0, GL_RGB, GL_FLOAT, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);

    glBindFramebuffer(GL_FRAMEBUFFER, _GL_Framebuffer);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, _GL_Texture, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    // In the actual code each texture is obviously saved in an object
}

GLenum *enums = new GLenum[BUFFER_COUNT];
for(unsigned int i = 0; i < BUFFER_COUNT; ++i)
{
    // Get index and validate
    int index = *(indices + i); // indices = writeIndices
    if(index < 0 || index >= maxAttachments)
    {
        delete[] enums;
        return false;
    }

    // Set index
    enums[i] = GL_COLOR_ATTACHMENT0 + index;
}

// Set indices
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _GL_Framebuffer);
glDrawBuffers(BUFFER_COUNT, enums);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

delete[] enums;

// OpenGL error check, no errors
Valerianaceous answered 11/8, 2012 at 13:54 Comment(4)
Is any of your FBO's multisampled?Babylon
Oo about that, I never set any parameters concerning multisampling, I don't know how FBOs handle that themselves, but I'd assume they currently follow default behavior. I'd appreciate a hint in the right direction about how to set a FBO's multisampling behavior xD Also note it does succesfully blit if the draw/read rectangles are equal, it only throws the error when they're not, or on some laptops (the laptops SHOULD support at lest OpenGL 3.2).Valerianaceous
You could take a look at this and this. It contains other possible causes also, because it's hard to guess here. Your example is way too long, can't you try to reproduce it in a line or 20?Babylon
Ok I've gone through each call and took out all OpenGL calls, see the bottom of the question for the actual blitting code and the framebuffer/texture creation.Valerianaceous
V
6

After some careful reading I found out the difference in multisampling was the problem. The 'main' FBO was setup by SFML, so by simply setting the anti aliasing level on startup to 0 the problem was partially solved.

It now blits if the draw/read rectangles are unequal in size, but it keeps crashing on some machines where it is SUPPOSED to work.

Valerianaceous answered 11/8, 2012 at 19:2 Comment(1)
How old are the drivers on those machines? There are some old drivers on which FBO's tend to misbehave (allthough, these are very old). edit: the trick is, if your src framebuffer is multisampled, you should be able to draw to a non-sampled fbo, but only one of equal size is guaranteed to work iirc. So maybe, on those platforms the default framebuffer is still multisampled. Bliting with unequal sizes but the same sample rate should work without limitations.Babylon

© 2022 - 2024 — McMap. All rights reserved.