在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);
}
}
}
答案 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?。