이론/그래픽스

드로우콜(Draw Call)

tsyang 2021. 11. 13. 23:13

드로우콜


CPU는 현재 프레임에 어떤 것을 그려야 할지 정하고, GPU에 오브젝트를 그리라고 명령을 호출하는데 이 명령이 바로 드로우 콜(Draw Call)이다. 

 

게임의 오브젝트를 화면에 렌더링하려면 우선 오브젝트가 렌더링 대상인지를 판단한다. 이러한 과정을 컬링이라고 한다. 컬링을 거친 오브젝트가 렌더링 되기 위해선 CPU에서 GPU에 다음의 정보를 줘야 한다.

  • 메시 정보
  • 텍스처 정보
  • 쉐이더 정보
  • 트랜스폼 정보
  • 알파 블렌딩 여부
  • 기타 등등

 

 

 

메시 텍스쳐 쉐이더등의 정보는 스토리지에 보관되어 있다가 CPU가 이를 읽어들여 CPU 메모리에 데이터를 올린다. 그 후 CPU메모리에 있는 정보들을 GPU 메모리로 복사한다. 정보들은 GPU 메모리에 있어야 GPU가 사용할 수 있다.

 

만약 위 복사과정이 매 프레임마다 일어난다면 성능을 많이 잡아먹을 것이다. 따라서 로딩 시점에 데이터를 미리 메모리에 올려둔다. 

 

오브젝트를 렌더링하기 시작하면 GPU에 어떤 텍스처를 사용 할지, 어떤 버텍스들을 사용 할지, 어떤 쉐이더를 사용 할지등을 순차적으로 알려줘야 한다. 이런 정보들은 GPU의 상태 정보를 담는 테이블에 저장된다. 이 테이블을 렌더 상태(Render States)라고 부르며 각각의 요소는 GPU 메모리를 가리키는 포인터를 저장한다. 

 

Render States에는 알파 블렌딩 여부, Z테스트 여부, 기타 등등의 정보도 포함됨

CPU가 렌더 상태를 변경하는 명령을 GPU에 보내고 나면 CPU는 마지막으로 GPU에 메시를 그리라는 명령을 보낸다. 이 명령을 Draw Primitive Call(DP Call)이라고 부른다. GPU는 DP Call을 받으면 렌더 상태의 정보들을 마탕으로 오브젝트의 메시를 렌더링한다.

 

한 오브젝트의 메시가 렌더링 됐다면 CPU는 또 다른 오브젝트를 렌더링 하기 위해 사용할 쉐이더, 메시, 텍스쳐등의 정보들을 변경하는 명령을 한다. 그렇게 되면 Render States역시 바뀔 것이다. 그 후 DP Call을 받은 GPU가 다시 오브젝트를 렌더링한다. 

 

이처럼 한 오브젝트를 그릴 때마다 CPU가 매번 렌더 상태 정보들을 변경하라는 명령을 한 뒤, DP Call을 해준다. 이런 과정을 넓은 의미에서 드로우 콜이라고 한다.

 

CPU가 GPU에 명령을 보낼 때 명령들을 잠시 저장하는 버퍼가 존재하는데 이를 커맨드 버퍼라고 부른다. 커맨드 버퍼가 존재함으로써 CPU와 GPU는 서로 비동기적으로 일을 처리할 수 있다. 이런 커맨드 버퍼는 그래픽스 API마다 구현 방식이 다르며 여러 개의 커맨드 버퍼나 여러 개의 쓰레드를 사용하기도 한다.

 

문제는 드로우 콜에서 사용되는 명령들이 모두 GPU가 알아들을 수 있는 명령들로 변환되어야 하는데 이것이 CPU 오버헤드를 발생시키며 따라서 드로우 콜은 대게 CPU 병목의 주 원인이다.

 

드로우 콜로 인한 병목을 줄이기 위해선 드로우 콜 호출 횟수 자체를 줄여야 한다.

 

 


드로우 콜의 발생 조건

 

기본적으로 오브젝트를 그릴 때 메시가 1개, 머테리얼이 1개라면 드로우콜이 한 번 일어난다.

 

메시가 여러 개이면 드로우 콜도 여러 번 일어난다. 예를 들어, 한 오브젝트의 메시가 10개라면 해당 오브젝트를 렌더링 하는데 드로우 콜이 10번 발생한다. 만약 10개의 메시로 이뤄진 오브젝트가 20개 있다면 드로우 콜은 200번 발생하게 된다. 따라서 오브젝트의 파츠는 적을 수록 좋다.

 

마찬가지로 메시가 1개이지만 머티리얼이 여러 개인 경우에도 여러 번의 드로우콜이 발생한다. (서브 메시 생성)

 

쉐이더 내에서 멀티패스(Multi Pass)로 두 번 이상 렌더링을 하는 경우도 드로우 콜이 여러 번 발생한다. (ex. 카툰 렌더링 쉐이더에서 추가적으로 외곽선을 그려주는 경우)

 


 

Batch & Set Pass

유니티에서는 Batch와 Set Pass를 구분하는데, Batch는 넓은 의미의 드로우 콜이고 Set Pass는 쉐이더로 인한 렌더링 패스 횟수이다. 오브젝트를 렌더링 하는 중 머티리얼이 바뀌면 쉐이더 및 파라미터들이 바뀌면서 SetPass가 증가한다. 이 때 많은 상태 변경들이 일어나기 때문에 SetPass도 CPU 성능을 꽤 잡아먹는다.

 

예를 들어, 10개의 오브젝트가 같은 메테리얼을 사용한다면 Set Pass 횟수는 1이다. 그러나 10개의 오브젝트가 각기 다른 메테리얼을 사용한다면 Set Pass 횟수는 10이 된다. 그러나 서로 다른 메시를 사용하더라도 모두 동일한 머티리얼을 사용한다면 SetPass는 한 번만 발생한다.

 

 

'이론 > 그래픽스' 카테고리의 다른 글

컬링(Culling)  (0) 2021.12.14
배칭(Batching)  (2) 2021.11.15
병목(Bottleneck)  (0) 2021.11.03
렌더링 파이프라인  (1) 2021.10.26
곡선(Curve) & 스플라인(Spline)  (2) 2021.07.11