我一直在编译顶点着色器时遇到间歇性错误,为新创建的OpenGL上下文做第一次渲染的准备。这是通常能够正常工作的同样的顶点着色器,在同样的硬件上。失败后,glGetShaderInfoLog
返回的信息日志通常会显示如下内容:
Vertex shader failed to compile with the following errors:
是的,就是这样。它发生在Windows上,使用ATI和NVidia GPU,尽管我主要在ATI上进行测试。如果我在Visual Studio调试器下运行,则可能会检测到glCompileShader
或随后的glGetShaderiv
调用中的访问冲突。
我没有在Mac上看到这个错误,但由于不总是容易重现它,我不能确定它不会发生。
我注意到,如果我在创建上下文时不调用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上下文,以相同的方式进行初始化,但顶点着色器无法编译。
如果不渲染任何几何图形,则无法重现错误,但渲染一个点就足够了。
即使使用简化的顶点着色器仍然会发生这种情况:
#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 );
然后错误消失了。但是在重新引入更多真实世界的渲染(例如纹理)后,它似乎并没有什么区别。
2014年3月7日添加:我最终制作了一个自包含的Visual C++项目,可以在某些情况下重现错误,以便任何感兴趣的人都可以尝试:ShaderBugTest project 为了使错误能够重现,您需要将Microsoft的“应用程序验证器”设置为监视堆错误。附带的Read Me有更详细的重现步骤。