2014-07-22 31 views
0

在OpenGL管道之前:我想爲我渲染的某些對象使用特殊的頂點着色器。所以我想這個:OpenGL:爲着色器創建代理用戶

int currProgram = glGetInteger(GL_CURRENT_PROGRAM); 
int currVertexShader = 0; 
if (currProgram == 0) { 
    glUseProgram(programName); 
} else { 
    currVertexShader = GLStatics.getShader(currProgram, 
      GL_VERTEX_SHADER); 
    if (currVertexShader != 0) { 
     glDetachShader(currProgram, currVertexShader); // <-- problem here 
    } 
    glAttachShader(currProgram, shaderName); 
    GLStatics.linkProgramSafe(currProgram); 
} 
// Actual render code 
if (currProgram != 0) { 
    glDetachShader(currProgram, shaderName); // Can safely detach 
    if (currVertexShader != 0) { 
     glAttachShader(currProgram, currVertexShader); 
    } 
    GLStatics.linkProgramSafe(currProgram); 
} 
glUseProgram(currProgram); 

所以我要靜GLObjects:shaderName,這是編譯頂點着色器我想使用programName這是我綁定,如果沒有其他程序勢必beforehands程序。

我以爲這會運行良好時,真的有問題。在執行代碼之前,在當前綁定程序的頂點着色器上調用glDeleteShader()時,着色器對象將被刪除(在標記的行中),並且之後無法重新附加。

有沒有一種簡單的方法來解決這個問題(在高效的意義上容易)?

爲了完整起見,GLStatics類:

public class GLStatics { 
    public static ByteBuffer createDirectBuffer(int size) { 
     return ByteBuffer.allocateDirect(size); 
    } 

    public static int createProgramSafe() { 
     int programName = glCreateProgram(); 
     if (programName == 0) { 
      throw new IllegalStateException(
        "GL Error: Created Program is 0. Can't proceed."); 
     } 
     return programName; 
    } 

    public static int getShader(int program, int searchedType) { 
     int shaderCount = glGetProgrami(program, GL_ATTACHED_SHADERS); 
     IntBuffer attachedShaders = createDirectBuffer(shaderCount * 4) 
       .asIntBuffer(); 
     IntBuffer count = createDirectBuffer(4).asIntBuffer(); 
     glGetAttachedShaders(program, count, attachedShaders); 
     assert count.get() == shaderCount; 
     for (int i = 0; i < shaderCount; ++i) { 
      int shaderCandidate = attachedShaders.get(); 
      if (searchedType == glGetShaderi(shaderCandidate, GL_SHADER_TYPE)) { 
       return shaderCandidate; 
      } 
     } 
     return 0; 
    } 

    public static void linkProgramSafe(int program) { 
     glLinkProgram(program); 
     if (glGetProgrami(program, GL_LINK_STATUS) == GL_FALSE) { 
      int errorLength = glGetProgrami(program, GL_INFO_LOG_LENGTH); 
      String error = glGetProgramInfoLog(program, errorLength); 
      throw new IllegalStateException(error); 
     } 

    } 
} 

回答

1

你可以有,而它是從你運行的着色器分離,你只需要使用的「停車場」的着色器的另一個着色器程序。這將保持一個參考,防止它被刪除的好。

就顯示代碼的擴展部分,與dummyProgram是你只創建用於此目的的程序:

if (currVertexShader != 0) { 
    glAttachShader(dummyProgram, currVertexShader); 
    glDetachShader(currProgram, currVertexShader); 
} 
... 
if (currVertexShader != 0) { 
    glAttachShader(currProgram, currVertexShader); 
    glDetachShader(dummyProgram, currVertexShader); 
} 

這將工作基於規範的定義如下(附錄D.1.2在OpenGL 3.3規格):

當着色器對象或程序對象被刪除,它被標記爲刪除,但它的名字仍然有效,直到底層的對象可以被刪除,因爲它不再使用。着色器對象在附加到任何程序對象時正在使用。

所以只需將着色器附加到任何程序就足以使其被視爲「正在使用」,並防止它被刪除。如果您對程序/着色器生命週期細微方面的更多細節感興趣,這是我寫給以前問題的一個答案:glDeleteShader - is the order irrelevant?

+0

附加着色器就夠了,我沒有鏈接它?你知道比沒有它慢多少? – WorldSEnder

+0

是的,附加就夠了。我在答案中增加了一些更詳細的說明。增加的開銷應該是最小的。這不是你想要在一個緊密的循環中做的事情,但是你要用相同的代碼連接一個着色器程序,這可能是數量級更昂貴的。 –