Quick Comparison
여러 명령을 합쳐도 프로그램·VAO·출력 상태가 명령마다 자동으로 바뀌지는 않습니다. 호환되는 상태와 자료 배치를 먼저 묶습니다. 대응 ARB 확장 경로는 코어 지원과 따로 확인합니다.
| 경로 | 기준 코어 버전 | 명령 입력 |
|---|---|---|
| draw 반복 | 사용하는 draw에 따름 | CPU가 호출마다 인수 지정 |
| MultiDraw | 1.4 | CPU 배열에 여러 범위 |
| DrawIndirect | 4.0 | 버퍼에 draw 인수 |
| MultiDrawIndirect | 4.3 | 버퍼에 여러 명령 |
| IndirectCount | 4.6 | 명령 개수도 버퍼에서 읽기 |
명령 구조
DrawElementsIndirect의 명령은 다섯 개의 32비트 필드입니다. C++에서는 <cstdint>의 고정 폭 타입을 사용하고 layout을 맞춥니다.
struct DrawCommand {
std::uint32_t count;
std::uint32_t instanceCount;
std::uint32_t firstIndex;
std::int32_t baseVertex;
std::uint32_t baseInstance;
};
static_assert(sizeof(DrawCommand) == 20);count는 인덱스 개수, firstIndex는 EBO 안의 인덱스 단위 시작점입니다. 일반 DrawElements 마지막 인수의 바이트 오프셋과 다릅니다. indirect 호출의 포인터 인수는 다시 명령 버퍼 안 바이트 오프셋이므로 세 값을 구분합니다. 4.0 경로의 마지막 필드는 예약되어 0으로 두며, baseInstance 의미는 4.2 이후를 확인합니다.
연결 조건
// GL 4.3 Core: commandBuffer에 drawCount개 유효 명령이 저장되어 있습니다.
glBindVertexArray(vao); // 정점 속성과 EBO 연결 포함
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT,
nullptr, drawCount, sizeof(DrawCommand));프로그램·출력 상태도 준비되어야 합니다. stride는 명령 간 바이트 간격이고 0은 명령을 밀집 배치한 경우입니다. 각 명령이 가리키는 정점·인덱스·인스턴스 범위가 유효해야 합니다. 큰 버퍼 한 개에 들어 있다는 사실만으로 범위가 자동 검증되는 것은 아닙니다.
GPU가 명령을 만들 때
Compute가 명령 버퍼를 썼다면 다음 indirect 소비 전에 COMMAND_BARRIER_BIT 등 실제 소비자에 맞는 가시성을 확보합니다. 명령 개수와 저장 가능한 최대 개수를 제한합니다. 특히 indirect dispatch의 잘못된 값은 직접 dispatch와 같은 수준의 인수 검사를 기대할 수 없으므로 생성 범위를 설계에서 보장해야 합니다.
4.6 IndirectCount는 parameter buffer에서 개수를 읽되 CPU가 지정한 최대 개수도 사용합니다. 개수는 GL_PARAMETER_BUFFER에 바인딩한 버퍼에서 읽고, drawcount 인수는 그 버퍼 안의 4바이트 정렬된 바이트 오프셋입니다. GL_DRAW_INDIRECT_BUFFER에 담은 명령 배열과 별개의 바인딩이며, maxdrawcount는 GPU가 기록한 개수를 제한하는 상한입니다. ARB 확장 경로에서는 해당 접미사와 상수를 구분합니다. 기본 4.3 MultiDrawIndirect와 같은 기능으로 묶지 않습니다.
배치의 비용
불투명 패스의 상태 정렬과 투명 패스의 깊이 순서는 서로 다른 요구입니다. draw 수를 줄이려고 투명 순서를 깨지 않습니다. CPU 제출 병목이 아닌 장면에서는 명령 통합의 이득이 작을 수 있습니다. 인스턴싱·시간 쿼리와 함께 선택 기준을 봅니다.
참고 링크
4 sources