2014-07-22 23 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

是的,附加就够了。我在答案中增加了一些更详细的说明。增加的开销应该是最小的。这不是你想要在一个紧密的循环中做的事情,但是你要用相同的代码连接一个着色器程序,这可能是数量级更昂贵的。 –