2014-07-22 4 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에 있습니다 : 내가 사용하려는 컴파일 된 버텍스 쉐이더입니다 shaderNameprogramName을 다른 프로그램이 beforehands을 구속하지 않을 경우 나는 결합하는 프로그램이다.

정말 문제가있을 때 정상적으로 실행될 것이라고 생각했습니다. 코드를 실행하기 전에 현재 바인딩 된 프로그램의 버텍스 쉐이더에서 glDeleteShader()가 호출되면 쉐이더 객체가 삭제되고 (나중에 표시된 라인에서) 다시 연결할 수 없습니다.

효율적인 방법으로이 문제를 쉽게 해결할 수 있습니까?

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

당신은 그것이 당신이 운영하고있는 쉐이더에서 분리하는 동안에 당신이 "주차"쉐이더를 위해 단지 사용하는 다른 쉐이더 프로그램을 할 수 : 완성도를 위해서 GLStatics 클래스

. 그러면 삭제 된 것을 유지하는 참조가 유지됩니다. 이것은 OpenGL을의 사양에 다음과 같이 정의 (부록 D.1.2에 따라 작동합니다

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

:

그냥이 목적으로 만 만들어진 프로그램 인 dummyProgram으로, 코드의 확장 부분을 보여주는 3.3 사양) :

셰이더 개체 또는 프로그램 개체를 삭제하면 삭제 플래그가 지정되지만 더 이상 사용되지 않으므로 기본 개체를 삭제할 수있을 때까지 해당 이름이 유효합니다. 셰이더 개체는 모든 프로그램 개체에 첨부되어있는 동안 사용 중입니다.

셰이더를 프로그램에 연결하는 것만으로 "사용 중"으로 간주되어 삭제되지 않도록 할 수 있습니다. 프로그램/쉐이더 수명의 미묘한 측면에 대한 자세한 내용은이 질문에 대한 답변입니다 : glDeleteShader - is the order irrelevant?.

+0

쉐이더를 연결하는 것으로 충분합니다. 링크하지 않아도됩니까? 이것이없는 것보다 이것이 얼마나 더 느린 지 아십니까? – WorldSEnder

+0

예, 부착만으로 충분합니다. 나는 그 대답에 spec quote를 더 자세히 설명했다. 추가되는 오버 헤드는 최소화되어야합니다. 이것은 단호한 루프에서하고 싶지는 않지만, 동일한 코드에서 쉐이더 프로그램을 링크하고 있습니다. 아마 이것은 더 큰 규모의 명령 일 것입니다. –