-
2. CPU와 GPU의 상호작용Software/DirectX 2024. 5. 24. 09:15728x90
Table of Contents
1. 명령대기열
2. CPU와 GPU의 동기화 작업 Fence
3. 자원 상태 전이 장벽(transition resource barrier)
4. 명령 목록 다중스레딩1. 명령대기열(Command Queue)
그래픽 프로그래밍에는 CPU와 GPU가 사용되며 둘은 병렬로 돌아간다. 최적의 성능을 얻으려면 두 처리 장치 모두 바쁘게 돌아가야하며 동기화를 최소화 하여야한다. 동기화는 한 처리장치가 작업을 마칠때까지 다른 장치가 처리를 멈추고 대기해야함을 의미하기 때문이다. 따라서 동기화는 병렬성을 망친다.
일반적으로 CPU는 명령대기열(Command Queue)에 GPU가 처리할 작업을 DirectX를 통해 제출한다. GPU는 명령대기열에서 명령을 순차대로 뽑아서 그리기를 수행한다. 커맨드 큐가 비거나 꽉차면 CPU나 GPU중 하나가 놀기때문에 바람직하지 않다.
명령대기열을 다루는 API는 ID3D12CommandList이다. 하지만 실제로 그래픽작업에서 사용하는 매서드는 이 API를 상속한 ID3D12GraphicsCommandList이다. 해당 인터페이스는 뷰포트를 설정하고 렌더타겟뷰를 지우고 그리기를 호출하는 그리기 작업 전반을 설정한다.
- 명령대기열 주요 매서드 mCommandList->RSSetViewports(~~~); mCommandList->ClearRenderTargetView(~~); mCommandList->DrawIndexedInstanced(~~~); mCommandList->Close();
이 작업은 바로 실행되는 것이 아닌 커맨드 큐에 그리기명령 하나를 전송하기 위해 셋업하는 작업이다. 따라서 ExcuteCommandLists로 명령목록을 제출해야 하는데, 제출하기 전에 꼭 Close()로 명령 목록이 끝났음을 D3D에 알려야함을 잊지 말자.
CommandList를 동시에 두개 작성해서는 안된다. 하나를 작성하는 동안에는 해당 명령이 인접해서 저장되기 때문이다. 따라서 하나를 작성해서 제출한 후에 CommandList::Reset()을 호출하여 커맨드 리스트를 리셋시키고 새로 작성해서 제출하여야 한다.
CommandList로 제출한 명령은 바로 커맨드 큐로 가는것이 아니라 CommandAllocator에 들어가게 된다. 커맨드 큐는 Allocator에서 명령을 참조한다.
Allocator가 있는 이유는 해당 커맨드리스트를 리셋해도 Allocator에 이전에 보낸 메세지가 남아있기 때문에 커맨드 큐가 참조할때 혼동이 없기 때문이다. 따라서 커맨드리스트는 리셋으로 계속 재사용해도 상관이 없다.GPU에 모든 명령을 제출하고 난 후에는 Allocator도 Reset을 시켜서 다음 명령을 위한 준비를 해야한다. 이 때 GPU가 할당자에 담긴 모든 명령을 실행했음이 확실하기 전까지는 할당자를 재설정하면 안된다.
Vector Clear와 비슷하다. 이는 크기는 0이 되지만 용량(capacity)는 변하지 않는다.2. CPU와 GPU의 동기화 작업 Fence
GPU가 할당자에서 그리기 정보를 가져다 쓰기 전에 CPU가 할당자 정보를 덮어쓰면 제대로된 그림이 그려지지 않는다. 이를 방지 하기 위해 Fence를 세워서 GPU가 명령대기열의 어느 지점까지 명령을 처리하기 전까지 CPU가 기다리게 하는 것을 Flush(방출한다)라고 한다. 이 때 필요한 것이 Fence 객체이다. 따라서 Fence객체는 CPU와 GPU의 동기화 수단으로 사용된다.
Fence는 간편한 해결책이지만 CPU가 대기하는 시간이 많아 낭비가 발생한다. 따라서 후에 다른 처리방법을 설명한다3. 자원 상태 전이 장벽(transition resource barrier)
GPU가 자원 R에 자료 기록하기 전에 다른 곳에서 읽으려하면 문제가 된다. 이 구역을 resource hazard라고 한다. 일종의 임계구역으로, 이를 해결하기 위해 D3D에서는 자원들에 상태(State)를 부여한다.기본 default state에서 읽어야 할때 자원상태로 변경하여 자원에 접근한다.
이때 전이 자원 장벽을 배열을 설정해서 지정한다. 이는 D3D12_RESOURCE_BARRIER_DESC구조체로 저장해서 넘겨준다. 해당 개체를 가지고 있는 구조체들은 대부분 d3dx12.h에 정의되어 있지만 공식 SDK가 아니라서 따로 내려받아야한다. GPU는 해당 장벽 구조체를 읽고 자원 해저드를 피하게 된다.4. 명령 목록 다중스레딩
물체가 많은 장면을 표현해내기 위해서는 CPU가 명령 목록을 만드는데 시간이 매우 오래 걸리게 된다. 이를 해결하기 위해 멀티쓰레딩으로 명령 목록을 넘겨주면 처리속도가 1/n까지 줄어들게 된다. 이 때 주의 사항이 있다
CommandList(명령 목록)과 CommandAllocator(명령 할당자)는 스레드당 하나, Command Queue는 프로그램당 하나, 따라서 명령 목록과 할당자를 멀티로 처리해서 큐에 우겨넣어 준다는 개념이다. 성능상의 이유로, 프로그램은 동시에 기록할 수 있는 명령 목록 최대 개수를 초기화 시점에서 정의해야한다.
728x90'Software > DirectX' 카테고리의 다른 글
6. 입력조립기 ( Input Assembler ) (0) 2024.05.24 5. 파이프라인과 3차원 표현 (0) 2024.05.24 4. 타이머 (0) 2024.05.24 3. DirectX 초기화 (0) 2024.05.24 1. DirectX 기초 (0) 2024.05.24