C++ 间歇GLSL顶点着色器编译错误

C++ 间歇GLSL顶点着色器编译错误,c++,windows,opengl,glsl,C++,Windows,Opengl,Glsl,我在编译顶点着色器时遇到间歇性错误,为新创建的OpenGL上下文的第一次渲染做准备。它与通常在同一硬件上工作的顶点着色器相同。失败后,glGetShaderInfoLog返回的信息日志通常显示以下内容: Vertex shader failed to compile with the following errors: 是的,就是这样。它发生在Windows上,使用ATI和NVidia GPU,尽管我主要是在ATI上进行测试。如果我在Visual Studio调试器下运行,则可能会在glCom

我在编译顶点着色器时遇到间歇性错误,为新创建的OpenGL上下文的第一次渲染做准备。它与通常在同一硬件上工作的顶点着色器相同。失败后,
glGetShaderInfoLog
返回的信息日志通常显示以下内容:

Vertex shader failed to compile with the following errors:
是的,就是这样。它发生在Windows上,使用ATI和NVidia GPU,尽管我主要是在ATI上进行测试。如果我在Visual Studio调试器下运行,则可能会在
glCompileShader
或随后的
glGetShaderiv
调用中检测到访问冲突

我还没有在Mac上看到这个bug,但由于它并不总是很容易复制,我不能绝对肯定它不会发生

我注意到,如果我在创建上下文时不调用
wglShareLists
,错误就会消失(或者至少我不能很容易地重现它)。我认为这意味着一些不好的信息正在从以前创建的(可能是以前破坏的)OpenGL上下文流到新的上下文。然而,我一直在删减内容,直到没有什么东西可以共享:没有纹理对象、显示列表、VBO、PBO。据我所知,剩下的唯一可以共享的东西就是着色器和程序对象

为窗口创建OpenGL上下文后,我大致如下初始化着色:

// Program initialization
GLint vertexShader = glCreateShader( GL_VERTEX_SHADER );
glShaderSource( vertexShader, 1, &vertexShaderSource, NULL );
glCompileShader( vertexShader );
GLint   status;
glGetShaderiv( vertexShader, GL_COMPILE_STATUS, &status );
if (status == GL_TRUE)
{
    GLint fragmentShader = glCreateShader( GL_FRAGMENT_SHADER );
    glShaderSource( fragmentShader, 1, &fragShaderSource, NULL );
    glCompileShader( fragmentShader );
    glGetShaderiv( vertexShader, GL_COMPILE_STATUS, &status );
    if (status == GL_TRUE)
    {
        GLint program = glCreateProgram();
        if (program != 0)
        {
            glAttachShader( program, vertexShader );
            glAttachShader( program, fragmentShader );
            glLinkProgram( program );
            glDetachShader( program, fragmentShader );
            glDetachShader( program, vertexShader );
            glDeleteShader( fragmentShader );
            // check for link success...
        }
    }
}
else
{
    char logBuf[1024];
    glGetShaderInfoLog( vertexShader, sizeof(logBuf), NULL, (GLchar*)logBuf );
    LogToFile( (char*)logBuf );
}
然后我渲染多个帧,并在某个点进行清理

glDeleteProgram( program );
glDeleteShader( vertexShader );
并破坏OpenGL上下文。稍后,我在同一窗口中创建了一个新的OpenGL上下文,并以相同的方式初始化它,但顶点着色器无法编译

如果我不渲染任何几何体,我就无法让bug重现,但渲染一个点就足够了

使用简化的顶点着色器仍会发生这种情况:

#version 120
void main()
{
    gl_Position = ftransform();
    gl_FrontColor = gl_Color;
    gl_BackColor = gl_Color;
}
和简化的片段着色器:

#version 120
void main()
{
    gl_FragColor = gl_Color;
}
我尝试了AMD的CodeXL OpenGL调试器,将其设置为出错时中断。它只是告诉我编译失败了,我已经知道了

失败的OpenGL上下文位于先前创建、成功渲染和销毁了不同上下文的窗口上。重复使用那样的窗户没什么不对的,是吗?(我知道,一旦您调用了
SetPixelFormat
,就无法更改窗口的像素格式。我确保每次都使用相同的像素格式。)

补充:在裁剪渲染代码时,我发现如果我注释掉了这行

glEnable( GL_VERTEX_PROGRAM_TWO_SIDE );
然后错误消失了。但随着更多真实世界渲染(如纹理)的恢复,这似乎没有什么不同


3/7/2014补充:我最终制作了一个自包含的Visual C++项目,它可以在某些情况下重现bug,以便任何相关方都可以尝试:为了使错误重现,需要设置微软的“应用程序验证程序”来监视堆错误。随附的自述有更详细的复制步骤。

使用glGetShaderInfoLog查看编译错误消息。例如,请参见

您似乎没有向
gl\u Color
写入任何内容

gl\u Color
属性可以在不同的位置表示不同的内容

在顶点着色器中,
gl\u Color
表示用户使用
glColor*
glColorPointer
调用传递的逐顶点颜色属性

在片段着色器中,
gl_Color
表示正在渲染的三角形面的插值颜色

然而,这是一个固定的管道功能,在现代OpenGL中,
gl\u Color
被弃用。这可能就是你犯错误的原因。您需要使用以下代码获取编译器错误消息:

GLint   SuccessFlag = 0;
GLsizei Length      = 0;
GLsizei MaxLength   = 0;

glGetShaderiv( ShaderID, GL_COMPILE_STATUS,  &SuccessFlag );
glGetShaderiv( ShaderID, GL_INFO_LOG_LENGTH, &MaxLength   );

char* Log = ( char* )alloca( MaxLength );

glGetShaderInfoLog( ShaderID, MaxLength, &Length, Log );
在问题中添加日志将有助于更好地诊断问题


你使用什么版本的OpenGL?是核心配置文件还是兼容性配置文件?

您的示例中有大量GL对象的分配和解除分配,但几乎没有错误检查

vertexShader = glCreateShader( GL_VERTEX_SHADER );
需要检查返回值vertexShader,以确保其有效

glGetShaderiv( vertexShader, GL_COMPILE_STATUS, &status );
您获得此值,但不显示您正在检查状态

program = glCreateProgram();
同样,在开始使用之前,需要检查返回值

glAttachShader( program, vertexShader );
fragmentShader = glCreateShader( GL_FRAGMENT_SHADER );
glShaderSource( fragmentShader, 1, &fragShaderSource, NULL );
glCompileShader( fragmentShader );
在将片段着色器和顶点着色器附加到程序之前,应同时创建它们。如果有什么东西出了问题,你清理的时间就少了

 glGetShaderiv( fragmentShader, GL_COMPILE_STATUS, &status );
再次检查获取后的编译状态。编译失败,但到目前为止,我们不知道哪个着色器无法编译。它是片段着色器还是顶点着色器

 glAttachShader( program, fragmentShader );
 glDeleteShader( fragmentShader );
在这里删除着色器很奇怪。是的,它应该只标记为删除,因为它实际上是附加到程序的,但这样做似乎仍然是一种危险的方式。此外,您正在采用与顶点着色器不同的方法来管理片段着色器,这没有明显的原因

 glLinkProgram( program );
 glDetachShader( program, fragmentShader );
 glDetachShader( program, vertexShader );
同样,对我来说,这是一种有点令人困惑的着色器管理方法。同样,以类似方式处理片段着色器和顶点着色器

 glDeleteProgram( program );
 glDeleteShader( vertexShader );
为什么片段着色器的处理方式不同


在诊断问题时,应使用
glGetError()
,并在每次GL调用后报告任何异常情况时停止程序,以便隔离第一个错误发生的位置。编译失败完全有可能是之前发生的某件事情的级联效应

我确实收到了编译错误消息,我在我的问题的前面告诉了你它是什么。是“顶点着色器未能编译并出现以下错误:”实际错误,还是从代码中打印的前缀?介意发布用于打印错误的代码吗?这是从驱动程序中检索到的实际信息日志文本,而不是我的代码。我将把代码添加到我的问题中。顺便说一下,我可以理解为什么您可能会认为“顶点着色器无法编译,出现以下错误:”可能是m提供的前缀