【问题标题】:glDrawBuffers causes GL_INVALID_OPERATION when setting GL_COLOR_ATTACHMENT1 as GL_DRAW_BUFFER0当将 GL_COLOR_ATTACHMENT1 设置为 GL_DRAW_BUFFER0 时,glDrawBuffers 会导致 GL_INVALID_OPERATION
【发布时间】:2017-03-24 22:01:06
【问题描述】:

iOS 上使用 OpengGL ES 3.0,我想使用一个片段着色器使用一个帧缓冲区对象(不是同时)绘制到 2 个不同颜色的附件( FBO)。但是,我在调用时收到 GL_INVALID_OPERATION 错误:

const GLenum attachments[] = {GL_COLOR_ATTACHMENT1};
glDrawBuffers(1, attachments);

我检查了 GL 状态并确保当前绑定了正确的 FBO,并且在此调用之前没有 GL_ERROR 并且 GL_MAX_COLOR_ATTACHMENTS 为 4。在 Xcode 中拍摄 GPU 快照会给出以下错误描述:

指定的操作对当前OpenGL状态无效

我创建了一个带有 2 个颜色附件的帧缓冲区对象,如下所示:

// Assuming the FBO and the 2 requried textures were correctly generated

glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _fbo_tex[0], 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, _fbo_tex[1], 0);

// glCheckFramebufferStatus(GL_FRAMEBUFFER) returns GL_FRAMEBUFFER_COMPLETE

顶点着色器:

#version 300 es

uniform mat4 modelviewProjectionMatrix;
in vec4 position;

void main() {
    gl_Position = modelviewProjectionMatrix * position;
}

片段着色器:

#version 300 es

uniform lowp vec4 colorIn;
layout(location = 0) out lowp vec4 colorOut;

void main() {
    colorOut = colorIn;
}

这是渲染代码:

// Assuming the correct program and vertex array is bound

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo);
{
    const GLenum attachments[] = {GL_COLOR_ATTACHMENT0};
    glDrawBuffers(1, attachments);    // OK
    glClear(GL_COLOR_BUFFER_BIT);

    // Draw red quad to GL_COLOR_ATTACHMENT0
}
{
    const GLenum attachments[] = {GL_COLOR_ATTACHMENT1};
    glDrawBuffers(1, attachments);    // GL_INVALID_OPERATION Error
    glClear(GL_COLOR_BUFFER_BIT);

    // Draw green quad to GL_COLOR_ATTACHMENT1
}

奇怪的是,如果我将第二个 glDrawBuffers 调用替换为:

const GLenum attachments[] = {GL_NONE, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, attachments);    // OK
glClear(GL_COLOR_BUFFER_BIT);

但这不是所需的行为,因为片段着色器输出到绘制缓冲区位置 0。根据这篇 wiki 文章:https://www.khronos.org/opengl/wiki/Fragment_Shader#Output_buffers {GL_COLOR_ATTACHMENT1} 是 glDrawBuffers 的有效输入,所以这是 iOS 错误吗?任何帮助将不胜感激。

【问题讨论】:

    标签: ios opengl-es fragment-shader


    【解决方案1】:

    桌面 OpenGL 与 OpenGL ES 不同。出于某种原因,glDrawBuffers 的行为在 ES 中受到更多限制。特别是来自 ES 3.0 规范:

    如果 GL 绑定到绘图帧缓冲区对象并且第 i 个参数不是COLOR_ATTACHMENTiNONE 的值,则会生成INVALID_OPERATION 错误。

    注意最后一个子句:第 i 个参数必须是 GL_NONE 或者它必须使用与索引 i 相同的颜色附件索引。 OpenGL ES 3.0 不允许您将 FS 的输出位置 0 路由到颜色附件 1。该位置必须与附件索引匹配。

    为什么?我不知道,但这可能是由于支持 ES 3.0 的硬件的硬件限制。 ES 3.1 去掉了这个限制,桌面 GL 当然从来没有。

    【讨论】:

    • 感谢您的快速回复!鉴于 OpenGL ES 上不存在 glBindFragDataLocation,有没有办法动态更改片段着色器的输出索引?或者是创建两个相同着色器的唯一替代方法,一个具有 layout(location = 0) ...,另一个具有 layout(location = 1) ...,然后在各自的绘图调用之前切换程序?
    • @Chewy: glBindFragDataLocation 不允许您动态更改 FS 的输出索引。它仅在调用glLinkProgram 时生效。无论如何,您的选择是创建两个不同的程序或两个不同的 FBO。
    • 很高兴知道!如何创建一个将相同值写入 2 个输出的 FS:layout(location = 0)... 和 layout(location = 1),然后使用 glDrawBuffers(1, {GL_COLOR_ATTACHMENT0}) 和 glDrawBuffers(2, {GL_NONE, GL_COLOR_ATTACHMENT1) }) 分别在绘制调用之前?它可能超出了这个问题的范围,但是您对这三种替代方案的性能有任何经验吗?
    猜你喜欢
    • 2020-10-05
    • 2020-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    • 2021-04-10
    • 1970-01-01
    • 2018-12-01
    相关资源
    最近更新 更多