Quick Flow
단계별: CreateShader → ShaderSource → CompileShader
→ COMPILE_STATUS·shader log
조합: CreateProgram → AttachShader → LinkProgram
→ LINK_STATUS·program log → UseProgram
정리: shader 삭제 요청 → program 사용 종료·삭제컴파일 성공은 한 셰이더 소스가 유효하다는 뜻입니다. 정점·프래그먼트 단계가 함께 동작하는지는 프로그램 링크 결과를 따로 확인해야 합니다. 기본 예제는 GL 3.3 Core와 GLSL 330 core입니다.
단계별 컴파일
현재 GL 컨텍스트와 GLAD 초기화가 필요합니다. 다음 함수는 <cstdio>, <vector>와 GLAD 헤더를 포함한 C++ 파일에서 사용하며, 성공한 shader의 삭제 책임은 호출자에게 넘깁니다. 삼각형 전체 코드에도 같은 함수가 들어 있습니다.
GLuint compileShader(GLenum type, const char* source) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
GLint ok = GL_FALSE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
if (!ok) {
GLint length = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
std::vector<char> log(length > 0 ? length : 1);
glGetShaderInfoLog(shader, static_cast<GLsizei>(log.size()), nullptr, log.data());
std::fprintf(stderr, "Shader: %s\n", log.data());
glDeleteShader(shader);
return 0;
}
return shader;
}glShaderSource는 전달한 소스를 복사하므로 호출 뒤 CPU 문자열 저장소를 계속 유지할 필요는 없습니다. 명시적 길이를 제공하지 않는 이 예제의 문자열은 널 종료되어야 합니다. 파일을 읽었다면 경로·읽기 실패·빈 소스도 컴파일 이전에 확인합니다.
로그 길이에 맞춰 버퍼를 준비하면 긴 컴파일 진단이 고정 배열에서 잘리는 일을 피할 수 있습니다. 성공 여부는 로그가 비었는지가 아니라 GL_COMPILE_STATUS로 판단합니다. 드라이버에 따라 성공 시에도 경고가 있을 수 있습니다.
프로그램 링크
컴파일된 vertex와 fragment가 준비되어 있다는 전제의 발췌 코드입니다. 실패한 shader가 0이면 이 구간으로 넘어오지 않습니다.
GLuint program = glCreateProgram();
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
GLint linked = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &linked);
// 결과와 무관하게 shader의 소유권은 여기서 정리합니다.
glDeleteShader(vertex);
glDeleteShader(fragment);
if (!linked) {
GLint length = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
std::vector<char> log(length > 0 ? length : 1);
glGetProgramInfoLog(program, static_cast<GLsizei>(log.size()), nullptr, log.data());
std::fprintf(stderr, "%s\n", log.data());
glDeleteProgram(program);
program = 0;
} else {
glUseProgram(program);
}glDeleteShader는 연결된 shader를 즉시 무효화하는 호출이 아닙니다. 삭제를 요청해도 연결 등 참조가 남아 있으면 실제 정리는 지연될 수 있고, 링크된 프로그램의 실행 결과는 유지됩니다. 프로그램을 다 쓴 뒤에는 glUseProgram(0)으로 사용을 해제하고 glDeleteProgram으로 정리합니다.
실패 예제 읽기
정점 셰이더의 out vec3 tint를 프래그먼트 셰이더가 in vec4 tint로 실제 사용하면 두 소스의 문법은 각각 성립해도 링크의 인터페이스가 맞지 않습니다. 정점 위치를 쓸 때 gl_Position 철자를 틀린 경우는 단계 컴파일 문제입니다. 둘의 로그 조회 함수도 구분합니다.
glGetError가 0이라고 컴파일·링크가 성공했다고 결론 내리지 않습니다. 이 두 작업의 성공 여부는 각 상태 값으로 확인합니다. glValidateProgram은 현재 상태와의 검증에 쓰며 컴파일·링크 검사나 실제 출력 검증을 대신하지 않습니다.
버전과 재링크
셰이더 객체 API는 2.0에 코어로 들어왔지만 GLSL 330 소스를 2.0 환경에서 사용할 수 있다는 뜻은 아닙니다. 구형 attribute·varying과 현대 in·out을 버전 조건 없이 섞지 않습니다. 1.x의 고정 변환·조명 역할은 현대 경로에서 직접 작성한 셰이더와 CPU 입력으로 나뉩니다.
재링크 후 uniform 위치와 값은 다시 준비합니다. 개발 중 소스를 바꿀 때는 새 프로그램을 별도로 컴파일·링크하고 성공한 뒤 교체하면 마지막으로 정상 동작한 프로그램을 유지할 수 있습니다. 원래 프로그램에 실패한 링크를 반복하면서 이전 상태가 보존된다고 가정하지 않습니다.
참고 링크
3 sources