Quick Flow
관찰할 패스 범위 지정 → GPU query 기록
→ 다음 프레임의 다른 작업 진행 → RESULT_AVAILABLE 확인
→ 준비된 결과만 회수 → 제출·GPU·표시 대기를 구분해 해석CPU 함수 호출 시간을 잰 값은 GPU 실행 시간과 같지 않습니다. 쿼리 결과를 바로 요구하면 CPU 대기가 추가되어 원래 관찰하려던 동작을 바꿀 수 있습니다.
시간 쿼리
// GL 3.3 Core: query는 glGenQueries로 생성한 이름입니다.
glBeginQuery(GL_TIME_ELAPSED, query);
// 관찰할 draw 명령을 이 범위에 제출합니다.
glEndQuery(GL_TIME_ELAPSED);
// 이후 프레임 등에서 확인합니다.
GLuint ready = GL_FALSE;
glGetQueryObjectuiv(query, GL_QUERY_RESULT_AVAILABLE, &ready);
if (ready) {
GLuint64 nanoseconds = 0;
glGetQueryObjectui64v(query, GL_QUERY_RESULT, &nanoseconds);
}TIME_ELAPSED 결과는 나노초 단위이며 64비트로 받습니다. 같은 활성 target의 query를 중첩하지 않습니다. 결과를 읽기 전에 같은 query 객체를 새 측정으로 덮어쓰지 않도록 여러 프레임의 객체 수명을 관리합니다. 사용이 끝난 객체는 glDeleteQueries로 정리합니다.
무엇을 구분하는가
| 관찰 | 읽는 의미 | 오해 |
|---|---|---|
| CPU 제출 시간 | API 호출·드라이버 처리·CPU 대기 | GPU 셰이더 실행 시간과 동일시 |
| TIME_ELAPSED | GPU의 쿼리 구간 경과 | 다른 부하·스케줄 영향이 전혀 없다고 단정 |
| TIMESTAMP | GPU 타임라인 지점 | CPU 시계와 임의로 빼서 비교 |
| 표시 간격 | swap·동기화·창 시스템의 영향 | 순수 GPU 병목으로 단정 |
오프라인 프로파일링 수치 자체를 제공하는 문서가 아니라, 어떤 값을 읽고 무엇을 판단할지 설명합니다. 하나의 프레임으로 모든 환경의 성능을 결론 내리지 않습니다.
Occlusion Query
SAMPLES_PASSED나 ANY_SAMPLES_PASSED는 가림 판단에 사용할 수 있습니다. 그러나 이번 프레임 결과를 즉시 기다려 draw 여부를 결정하면 GPU·CPU가 직렬화될 수 있습니다. 이전 결과를 활용할 때는 카메라 이동·물체 변화 때문에 생기는 지연과 잘못된 숨김 정책을 고려합니다.
쿼리 자체도 draw와 상태 준비 비용이 있습니다. 작은 물체마다 별도 쿼리를 만들면 아끼는 작업보다 조회 비용이 클 수 있습니다. 조건부 렌더링은 결과 준비·모드에 따라 기다리는 동작이 달라지므로 단순한 if와 동일시하지 않습니다.
조건부 렌더링의 기본 mode는 GL_QUERY_WAIT, GL_QUERY_NO_WAIT, GL_QUERY_BY_REGION_WAIT, GL_QUERY_BY_REGION_NO_WAIT입니다. WAIT는 결과를 기다리고 NO_WAIT는 미준비 결과에서 그리기를 실행할 수 있습니다. 3.3에서는 SAMPLES_PASSED·ANY_SAMPLES_PASSED 쿼리를 사용하고, 4.3 또는 ARB_ES3_compatibility에서는 ANY_SAMPLES_PASSED_CONSERVATIVE도 조건부 렌더링에 사용할 수 있습니다. timer query를 조건부 렌더링 입력으로 쓰지 않습니다.
버전과 지원
기본 occlusion query는 1.5, timer query의 코어 경로는 3.3, 보수적 occlusion 결과는 이후 4.3 기능을 구분합니다. 4.4 query buffer 경로는 결과를 버퍼로 다루며 기본 CPU 포인터 결과 회수와 사용 조건이 다릅니다.
GPU 캡처 도구는 API·OS·드라이버 지원을 확인해 선택합니다. 쿼리 결과를 병목 유형으로 해석할 때는 Graphics GPU 병목의 모델을 함께 사용합니다.
참고 링크
5 sources