OpenGL:为着色器创建代理用户

时间:2014-07-22 00:23:55

标签: java shader opengl-2.0

在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是我绑定的程序,如果之前没有其他程序绑定。

我认为在遇到问题时这会很好。当在执行代码之前在当前绑定程序的顶点着色器上调用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 个答案:

答案 0 :(得分:1)

您可以使用另一个着色器程序,仅用于&#34;停车&#34;着色器,当它与您正在操作的着色器分离时。这将保留一个参考,以防止它被删除。

只显示代码的扩展部分,dummyProgram是您专门为此目的创建的程序:

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

这将基于规范中的以下定义(OpenGL 3.3规范中的附录D.1.2):

  

删除着色器对象或程序对象时,会将其标记为删除,但其名称仍然有效,直到可以删除基础对象,因为它已不再使用。着色器对象在附加到任何程序对象时正在使用。

因此,只需将着色器附加到任何程序就足以让它被视为&#34;在使用&#34;中,并防止它被删除。如果您对关于程序/着色器生命周期的细微方面的更多细节感兴趣,这是我在之前的问题中写的答案:glDeleteShader - is the order irrelevant?