【问题标题】:Opengl GL_QUADS produces error 0x506Opengl GL_QUADS 产生错误 0x506
【发布时间】:2012-05-10 12:05:50
【问题描述】:

我在 OpenGL 中有一些代码可以将 YUV 图像渲染到 OpenGL 视口上。该程序在 nvidia 卡上运行时没有问题,但在英特尔 HD 3000 上运行时会产生错误,遗憾的是它是目标机器。代码中标出了产生错误的点。

着色器程序是

// Vertex Shader
#version 120
void main() {
  gl_TexCoord[0] = gl_MultiTexCoord0;
  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

// fragment shader
#version 120
uniform sampler2D texY;
uniform sampler2D texU;
uniform sampler2D texV;
void main() {
  vec4 color;
  float y = texture2D(texY, gl_TexCoord[0].st).r;
  float u = texture2D(texU, gl_TexCoord[0].st).r;
  float v = texture2D(texV, gl_TexCoord[0].st).r;
  color.r = (1.164 * (y - 0.0625)) + (1.596 * (v - 0.5));
  color.g = (1.164 * (y - 0.0625)) - (0.391 * (u - 0.5)) - (0.813 * (v - 0.5));
  color.b = (1.164 * (y - 0.0625)) + (2.018 * (u - 0.5));
  color.a = 1.0;
  gl_FragColor = color;
};

然后我像这样运行程序:

GLuint textures[3];
glGenTextures(3, textures);

glBindTexture(GL_TEXTURE_2D, textures[YTEX]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glBindTexture(GL_TEXTURE_2D, textures[UTEX]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glBindTexture(GL_TEXTURE_2D, textures[VTEX]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glBindTexture(GL_TEXTURE_2D, 0);

GLsizei size = width * height;

GLvoid *y = yuv_buffer;
GLvoid *u = (GLubyte *)y + size;
GLvoid *v = (GLubyte *)u + (size >> 2);

glUseProgram(program_id);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE,
            GL_UNSIGNED_BYTE, y);
glUniform1i(glGetUniformLocation(program_id, "texY"), 0);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width >> 1, height >> 1, 0,
            GL_LUMINANCE, GL_UNSIGNED_BYTE, u);
glUniform1i(glGetUniformLocation(program_id, "texU"), 1);

glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, textures[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width >> 1, height >> 1, 0,
            GL_LUMINANCE, GL_UNSIGNED_BYTE, u);
glUniform1i(glGetUniformLocation(program_id, "texV"), 2);

glBegin(GL_QUADS);
glTexCoord2f(texLeft, texTop);
glVertex2i(left, top);
glTexCoord2f(texLeft, texBottom);
glVertex2i(left, bottom);
glTexCoord2f(texRight, texBottom);
glVertex2i(right, bottom);
glTexCoord2f(texRight, texTop);
glVertex2i(right, top);
glEnd();

// glError() returns 0x506 here

glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);

glUseProgram(0);

update 由于帧缓冲区发生错误,我发现它们的使用方式如下: 当程序被实例化时,会像这样创建一个帧缓冲区:

glViewport(0, 0, (GLint)width, (GLint)height);

glGenFramebuffers(1, &fbo_id);
glGenTextures(1, &fbo_texture);
glGenRenderbuffers(1, &rbo_id);

glBindTexture(GL_TEXTURE_2D, fbo_texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,
            GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);

glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbo_id);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
                          GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
                            GL_RENDERBUFFER_EXT, rbo_id);

GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);

glPushAttrib(GL_TEXTURE_BIT);

glBindTexture(GL_TEXTURE_2D, m_frameTexture->texture());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glPopAttrib();

YUV 图像拼接成瓦片,这些瓦片是通过在此 fbo 中渲染组装而成的。每当一帧开始时,就会执行此操作:

glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
glDrawBuffer(GL_BACK);

glViewport(0, 0, (GLint)width, (GLint)height);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, (double)width, 0.0, (double)height, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo_id);

然后执行上面的代码,在所有的瓦片组装在一起之后

glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
glPushAttrib(GL_VIEWPORT_BIT | GL_TEXTURE_BIT | GL_ENABLE_BIT);
glViewport(0, 0, width, height);

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);

glMatrixMode(GL_PROJECTION);
glPushMatrix();

glLoadIdentity();
glOrtho(0.0, (double)width, 0.0, (double)height, -1.0, 1.0);

glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();

glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);

glBindTexture(GL_TEXTURE_2D, fbo_texture);

glBegin(GL_QUADS);
glTexCoord2i(0, 0);
glVertex2f(renderLeft, renderTop);
glTexCoord2i(0, 1);
glVertex2f(renderLeft, renderTop + renderHeight);
glTexCoord2i(1, 1);
glVertex2f(renderLeft + renderWidth, renderTop + renderHeight);
glTexCoord2i(1, 0);
glVertex2f(renderLeft + renderWidth, renderTop);
glEnd();

glPopMatrix();

glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();

【问题讨论】:

  • 在 gDEBugger 下运行。这些操作中的任何一个都可能失败,您不能只在随机选择的地方调用 glError 一次。
  • 我在整个程序中都有 glGetError 。我只是简化了这里的代码。我知道它在那里失败了。
  • 0x506 是 GL_INVALID_FRAMEBUFFER_OPERATION,这可能是一个红鲱鱼。您是否在代码中使用任何 FBO?
  • 事实上我是这样做的,但我还没有弄清楚管道的哪一点

标签: c++ opengl glsl


【解决方案1】:

status之后的值是多少:

GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

如果值不是GL_FRAMEBUFFER_COMPLETE,OpenGL 在尝试从 FBO 读取时可能会阻塞。

glCheckFramebufferStatus docs 描述了它可以返回的其他(错误)值,以及导致它们的原因。

特别感兴趣的可能是:

如果当前绑定的帧缓冲区不是完整的帧缓冲区,那么 尝试使用帧缓冲区进行写入或 阅读。 这意味着渲染命令(glDrawArrays 和 glDrawElements) 以及读取帧缓冲区的命令 (glReadPixels、glCopyTexImage2D 和 glCopyTexSubImage2D)将 如果在调用时生成错误 GL_INVALID_FRAMEBUFFER_OPERATION 帧缓冲区不完整。

(强调我的)

根据您的 cmets 进行编辑:

用 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 解释文档:

并非所有帧缓冲区连接点都是完整的帧缓冲区连接。 这意味着正在发生以下情况之一:

  • 至少有一个附加了渲染缓冲区或纹理的附加点的附加对象不再存在,或者附加的图像的宽度或高度为零,
  • 颜色附加点附加了不可颜色渲染的图像。可呈现颜色的格式包括 GL_RGBA4、GL_RGB5_A1 和 GL_RGB565。
  • 深度附加点附加了不可深度渲染的图像。 GL_DEPTH_COMPONENT16 是唯一可深度渲染的格式。
  • 模板连接点附加了一个不可模板渲染的图像。 GL_STENCIL_INDEX8 是唯一可模板渲染的格式。

我们可以排除最后 2 个项目符号,因为您似乎没有使用深度或模板附件。剩下两个电话需要检查:

glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rbo_id);

来自opengl.org wiki on FBOs

当任何附件“不完整”时,您会得到 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT。完整性的标准是:

  • 图像的源对象仍然存在,并且具有与它附加的相同类型。
  • 图像的宽度和高度不为零。
  • 3D 或阵列纹理附件的层小于纹理的深度。
  • 图像的格式必须符合上面定义的连接点要求。颜色附件等的颜色可渲染格式。

wiki 提到 GL_COLOR_ATTACHMENTi​:

这些连接点只能将图像绑定到它们 可呈现颜色的格式。并非所有压缩图像格式 可渲染颜色,因此不能附加到 FBO。

再次检查 fbo_texture 和 rbo_id 是否仍然有效,并且它们的高度/宽度不是 0。最后,它可能是 fbo_texture 的格式。您已将其设置为 GL_RGBA8,但文档说有效选项 include GL_RGBA4、GL_RGB5_A1 和 GL_RGB565。我不确定这是否排除所有其他格式(例如您的 GL_RGBA8)。 wiki 似乎建议任何非压缩格式都可以使用。尝试将其切换到 GL_RGBA4,看看是否可行。

【讨论】:

  • 这在某种程度上有所帮助,我收到了这个 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 现在我必须弄清楚这是什么意思 ;)
  • 伙计,您的帮助很棒。我刚刚发现渲染缓冲区无效 glIsRenderbuffer(rbo_id) 返回 0。现在的问题是,这首先是如何发生的,以及如何防止它发生。
【解决方案2】:

glGetError 错误代码“粘住”并且不会自动清除。如果您的程序在开始时产生 OpenGL 错误,并且您稍后检查错误代码 1000 opengl 调用,错误将仍然存在。

因此,如果您想了解到底发生了什么,请在每次 OpenGL 调用后检查错误,或在循环中调用 glGetError,直到返回所有错误代码(如 OpenGL 文档所建议的那样)。

【讨论】:

  • 正如我在上面的 cmets 中提到的,我确实在整个程序中都有 glGetError,几乎在每个语句之后。其实这里的很多语句都是从其他函数调用的,或者是在其他类的方法中的,我这里就这么写了,方便阅读。
  • @Samatyon: “我就是这样写的” 所以,你写了一些其他的代码片段,而不是产生问题的代码片段。 “伟大的”。 “几乎在每个语句之后” 根据墨菲定律,您的 “几乎” 意味着在导致问题的语句之后没有错误检查。因为你没有说 哪一行 导致 glGetError 返回错误代码,这意味着你没有在每条语句之后进行错误检查。
  • 你不希望我放置近 500 行非 opengl 调用、事件处理程序和所有这些东西的代码。假设我很确定错误确实存在
【解决方案3】:

我解决了这个问题。这是一个扩展问题,导致渲染缓冲区对象消失。我基本上改变了这个

glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbo_id);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
                          GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
                            GL_RENDERBUFFER_EXT, rbo_id);

GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

为此

glBindRenderbuffer(GL_RENDERBUFFER, rbo_id);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);

glBindFramebuffer(GL_FRAMEBUFFER, fbo_id);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                          GL_TURE_2D, fbo_texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                            GL_RENDERBUFFER, rbo_id);

GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

然后它起作用了。我仍然想知道到底是什么问题,但到目前为止我对结果很满意。特别感谢@luke,他的回答帮助找到了问题的确切点。

【讨论】:

  • 您是否在使用 GLEW 之类的东西来引入扩展功能?我有点惊讶 glEXT 函数/常量的行为与 gl 版本不同,但我很高兴你让它工作。如果您弄清楚有什么区别,请发布。
  • 是的,我正在使用 GLEW,我也对这种行为感到惊讶,但如果一切正常,我不能抱怨。我希望我能有时间真正了解问题所在。
【解决方案4】:

确切地说,哪个命令会引发错误?尝试将GL_QUADS 替换为GL_TRIANGLE_FAN

【讨论】:

  • 使用 TRIANGLE_FAN 在一批中绘制多个四边形将导致四边形连接在一起,这会严重搞砸纹理。最好每个四边形使用两个三角形并使用 TRIANGLES 绘制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-30
  • 2016-08-10
  • 2018-11-01
  • 2017-04-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多