glBlitFramebuffer 无效操作

Posted

技术标签:

【中文标题】glBlitFramebuffer 无效操作【英文标题】:glBlitFramebuffer Invalid Operation 【发布时间】:2012-08-08 13:24:30 【问题描述】:

我一直在搞乱帧缓冲区并渲染到纹理,我发现需要对它们进行 blit。再次在某些机器上,我在glBlitFramebuffer 呼叫之后立即收到GL_INVALID_OPERATION。绑定到帧缓冲区的每个纹理都以完全相同的方式设置,所有相同的大小和参数。此外,当我尝试将整个纹理(之前已成功渲染到)blit 到另一个帧缓冲区时,只有要写入的目标“矩形”小于要读取的矩形(例如,当我想将它blit 到屏幕),它也会抛出一个GL_INVALID_OPERATION

编辑: 实际上,每当要读取和绘制的矩形具有不同的大小时,它总是会引发错误,因此我无法使用不同大小的纹理,或者相同大小但不同大小的“渲染到”区域...?

每次我对手动生成的帧缓冲区进行 blit 时,都会通过 glCheckFramebufferStatus 检查状态并始终返回 GL_FRAMEBUFFER_COMPLETE

-有史以来最大的片段-,请参阅下面的更短的“源代码”,显然有几个 C++ 错误且不完整,但它仅适用于 GL 调用

当我以屏幕帧缓冲区为目标(通过传递 NULL)调用视口的最后一个方法 (Viewport::blit) 时,会发生 OpenGL 错误。它首先设置自己的帧缓冲区的读取缓冲区(绘制缓冲区已经设置),然后调用 RenderTarget::blit,后者调用 glBlitFramebuffer。在 blit 方法中,它绑定了两个缓冲区,您可以看到它在那里调用了glCheckFramebufferStatus,但没有返回错误。

我一遍又一遍地阅读this,但我似乎找不到导致它的错误。当我 blit 颜色缓冲区时,我使用 GL_LINEAR,否则我使用 GL_NEAREST 所有颜色缓冲区都使用 GL_RGB32F 作为内部格式,深度缓冲区(我从不 blit)使用 GL_DEPTH_COMPONENT32F

EDIT,一个更简短的例子,只是接受了所有的 GL 调用并填充了我使用的参数

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

还有 Framebuffer/Texture 的创建:

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

【问题讨论】:

您的 FBO 是否有多重采样? 关于那个,我从来没有设置任何关于多重采样的参数,我不知道 FBO 自己如何处理这个问题,但我假设它们目前遵循默认行为。我很感激有关如何设置 FBO 的多重采样行为的正确方向的提示 xD 另请注意,如果绘制/读取矩形相等,它会成功地进行 blit,它只会在它们不相等时或在某些笔记本电脑上抛出错误(笔记本电脑至少应该支持 OpenGL 3.2)。 你可以看看this和this。它还包含其他可能的原因,因为在这里很难猜测。您的示例太长了,您不能尝试在一行或 20 行中重现它吗? 好的,我已经完成了每个调用并取出了所有 OpenGL 调用,请参阅问题的底部以了解实际的 blitting 代码和帧缓冲区/纹理创建。 【参考方案1】:

仔细阅读后,我发现多重采样的差异是问题所在。 “主”FBO 由 SFML 设置,因此只需将启动时的抗锯齿级别设置为 0,问题就部分解决了。

如果绘制/读取矩形的大小不相等,它现在会出现 blit,但它会在一些应该工作的机器上不断崩溃。

【讨论】:

这些机器上的驱动程序有多长时间了?有一些老司机在 FBO 上往往行为不端(尽管这些老司机都很老了)。编辑:诀窍是,如果您的 src 帧缓冲区是多重采样的,您应该能够绘制到非采样的 fbo,但只有一个相同大小的帧可以保证工作 iirc。所以也许,在那些平台上,默认的帧缓冲区仍然是多重采样的。大小不等但采样率相同的 Bliting 应该没有限制。

以上是关于glBlitFramebuffer 无效操作的主要内容,如果未能解决你的问题,请参考以下文章

Rails 3 无效的多字节字符(US-ASCII)

igraph:使用graph.edgelist而不是graph_from_data_frame时顶点名称无效[关闭]

如果 FRA 利用率过高,Oracle 19c 发送电子邮件通知

sql 咨询FRA

sql Consulta Tamanho FRA

sql fra detail usage.sql