簡體   English   中英

間歇性GLSL頂點着色器編譯錯誤

[英]intermittent GLSL vertex shader compile errors

我一直在編寫一個頂點着色器的間歇性錯誤,為新創建的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項目為了使錯誤可重現,您需要擁有Microsoft的“應用程序”驗證程序“設置為監視堆錯誤。 隨附的Read Me有更詳細的步驟來重現。

你的例子有很多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調用后報告任何異常情況時停止程序,以便您可以隔離第一個錯誤發生的位置。 編譯失敗完全有可能是之前發生的事情的級聯效應。

使用glGetShaderInfoLog查看編譯錯誤消息。 有關示例,請參閱http://www.opengl.org/wiki/Shader_Compilation#Shader_error_handling

看起來你沒有給gl_Color寫任何東西。

gl_Color屬性可以表示不同地方的不同事物。

在頂點着色器中, gl_Color表示用戶使用glColor*glColorPointer調用傳遞的每頂點顏色屬性。

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

但是,這是一個固定的管道功能, gl_Color在現代OpenGL中已被棄用。 這可能是您的錯誤背后的原因。 您需要使用以下代碼獲取編譯器錯誤消息:

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? 它是核心還是兼容性配置文件?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM