c++ - Opengl GL_QUADS 产生错误 0x506

标签 c++ opengl glsl

我在 OpenGL 中有一些代码可以将 YUV 图像渲染到 OpenGL 视口(viewport)上。该程序在 nvidia 卡上运行时没有问题,但在 Intel 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);

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

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 图像拼接成图 block ,通过渲染在此 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);

然后上面的代码被执行,所有的tile都拼好了

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();

最佳答案

status 的值是什么:

GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

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

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

特别感兴趣的可能是:

If the currently bound framebuffer is not framebuffer complete, then it is an error to attempt to use the framebuffer for writing or reading. This means that rendering commands (glDrawArrays and glDrawElements) as well as commands that read the framebuffer (glReadPixels, glCopyTexImage2D, and glCopyTexSubImage2D) will generate the error GL_INVALID_FRAMEBUFFER_OPERATION if called while the framebuffer is not framebuffer complete.

(强调我的)

根据您的评论进行编辑:

用 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。完整性标准是:

  • The source object for the image still exists and has the same type it was attached with.
  • The image has a non-zero width and height.
  • The layer for 3D or array textures attachments is less than the depth of the texture.
  • The image's format must match the attachment point's requirements, as defined above. Color-renderable formats for color attachments, etc.

wiki 说 GL_COLOR_ATTACHMENTi :

These attachment points can only have images bound to them with color-renderable formats. All compressed image formats are not color-renderable, and thus cannot be attached to an FBO.

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

关于c++ - Opengl GL_QUADS 产生错误 0x506,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10533609/

相关文章:

c - Material 着色不起作用

c++ - GLM + STL : operator == missing

javascript - THREE.js vertexShader 基于高度的颜色混合

c++ - 是否可以从混合的 C++/CLI 代码中调用 IronPython?

c++ - 如何使用用户定义的比较结构重置 C++ 映射

c++ - 奇怪的段错误

c++ - Berkelium渲染纹理

c++ - 如何使 doxygen 将命名空间成员包含到组页面中

opengl - 可移植 YUV 绘图上下文

opengl - 如何将 "add"深度信息发送到主帧缓冲区