Direct3D 11에서 Direct3D 12로의 중요한 변경 내용

Direct3D 12는 Direct3D 11 프로그래밍 모델과 상당히 다릅니다. Direct3D 12를 사용하면 앱이 그 어느 때보다 하드웨어에 가까워집니다. 하드웨어에 더 가까워짐으로써 Direct3D 12는 더 빠르고 더 효율적입니다. 그러나 Direct3D 12를 통해 속도와 효율성이 향상된 앱의 단점은 Direct3D 11보다 더 많은 작업을 담당한다는 것입니다.

Direct3D 12는 낮은 레벨의 프로그래밍으로 되돌아가는 것입니다. 즉, 파이프라인 전체 상태를 나타내는 개체, 작업 제출을 위한 명령 목록 및 번들, 리소스 액세스를 위한 설명자 힙 및 테이블과 같은 새로운 기능을 도입함으로써 사용자에게 게임 및 앱의 그래픽 요소에 대한 추가적인 제어 권한을 제공합니다.

앱은 Direct3D 12를 통해 속도와 효율성이 향상된 반면, Direct3D 11보다 더 많은 작업을 담당합니다.

명시적 동기화

  • Direct3D 12에서 CPU-GPU 동기화는 이제 앱의 명시적 책임이며 Direct3D 11에서처럼 더 이상 런타임에 의해 암묵적으로 수행되지 않습니다. 또한 이 사실은 Direct3D 12에서 파이프라인 위험에 대한 자동 점검이 수행되지 않는다는 것을 의미하므로 이는 다시 앱의 책임입니다.
  • Direct3D 12에서 앱은 데이터 업데이트의 파이프라인에 대한 책임이 있습니다. 즉, Direct3D 11의 “Map/Lock-DISCARD” 패턴이 Direct3D 12에서는 수동으로 수행되어야 합니다. Direct3D 11에서 GPU가 D3D11_MAP_WRITE_DISCARD함께 ID3D11DeviceContext::Map을 호출할 때 버퍼를 계속 사용하는 경우 런타임은 이전 버퍼 데이터 대신 새 메모리 영역에 대한 포인터를 반환합니다. 이를 통해 앱이 데이터를 새 버퍼에 저장하는 동안, GPU는 기존 데이터를 계속 사용할 수 있습니다. 앱에서 추가적인 메모리 관리는 필요 없으며, GPU에서 사용이 끝나면 이전 버퍼가 자동으로 재사용되거나 제거됩니다.
  • Direct3D 12에서는 모든 동적 업데이트(상수 버퍼, 동적 꼭짓점 버퍼, 동적 텍스처 등)가 앱에 의해 명시적으로 제어됩니다. 이러한 동적 업데이트에는 필수 GPU 펜스 또는 버퍼링이 포함됩니다. 앱은 더 이상 필요하지 않을 때까지 메모리를 사용할 수 있도록 하는 역할을 담당합니다.
  • Direct3D 12는 인터페이스의 수명에만 COM 스타일 참조 카운트를 사용합니다(디바이스 수명에 연결된 Direct3D의 약한 참조 모델을 사용함). 모든 리소스 및 설명 메모리 수명은 적절한 기간 동안 유지 관리해야 하는 앱의 단독 책임이며 참조 카운트되지 않습니다. Direct3D 11에서는 인터페이스 종속성의 수명을 관리하는 데에도 참조 카운트를 사용합니다.

실제 메모리 상주 관리

Direct3D 12 애플리케이션은 여러 큐, 다중 어댑터 및 CPU 스레드 간의 경합 조건을 방지해야 합니다. D3D12에서는 더 이상 CPU와 GPU를 동기화하지 않으며, 리소스 이름 변경이나 다중 버퍼링을 위한 편리한 메커니즘을 지원하지도 않습니다. 다른 처리 장치가 메모리를 사용하기 전에 복수의 처리 장치가 덮어쓰지 않도록 펜스를 사용해야 합니다.

Direct3D 12 애플리케이션은 GPU가 데이터를 읽는 동안 데이터가 메모리에 저장되어 있는지 확인해야 합니다. 각 개체에서 사용되는 메모리는 개체를 생성하는 동안 상주하게 됩니다. 이러한 메서드를 호출하는 애플리케이션은 GPU가 제거된 개체에 액세스하지 못하도록 펜스를 사용해야 합니다.

리소스 장벽은 매우 세분화된 수준에서 리소스 및 하위 리소스 전환을 동기화하는 데 사용되는 또 다른 유형의 동기화입니다.

Direct3D 12의 메모리 관리를 참조하세요.

파이프라인 상태 개체

Direct3D 11에서는 대규모 독립 개체 세트를 통해 파이프라인 상태를 조작할 수 있습니다. 예를 들어 입력 어셈블러 상태, 픽셀 셰이더 상태, 래스터라이저 상태 및 출력 병합기 상태를 모두 독립적으로 수정할 수 있습니다. 이 디자인은 비교적 높은 수준의 편리한 그래픽 파이프라인 표현을 제공하지만, 주로 다양한 상태가 상호 의존적이기 때문에 최신 하드웨어의 기능을 활용하지 않습니다. 예를 들어 많은 GPU는 픽셀 셰이더와 출력 병합기를 단일 하드웨어 표현으로 결합합니다. 그러나 Direct3D 11 API에서는 이러한 파이프라인 단계를 별도로 설정할 수 있으므로 디스플레이 드라이버는 그리기 시간까지가 아니라 상태가 완료될 때까지 파이프라인 상태의 문제를 해결할 수 없습니다. 이 스키마는 하드웨어 상태 설정을 지연시켜 오버헤드가 추가되고 프레임당 최대 그리기 호출 수가 감소됩니다.

Direct3D 12에서는 대부분의 파이프라인 상태를 생성 시 완료되는 변경 불가능 PSO(파이프라인 상태 개체)로 통합하여 이 스키마를 해결합니다. 하드웨어 및 드라이버는 즉시 PSO를 GPU 작업을 실행하는 데 필요한 하드웨어 기본 지침 및 상태로 변환할 수 있습니다. 여전히 사용자가 사용 중인 PSO를 동적으로 변경할 수 있지만, 이를 위해서는 하드웨어가 하드웨어 상태를 즉시 컴퓨팅하는 대신, 미리 컴퓨팅된 최소 상태를 하드웨어 레지스터에 직접 복사해야만 합니다. PSO를 사용하면 그리기 호출 오버헤드가 현저하게 감소하고, 프레임당 그리기 호출이 더 많이 발생할 수 있습니다. PSO에 대한 자세한 내용은 Direct3D 12에서 그래픽 파이프라인 상태 관리를 참조하세요.

명령 목록 및 번들

Direct3D 11에서는 GPU로 이동하는 단일 명령 스트림을 나타내는 직접 컨텍스트를 통해 모든 작업 제출이 수행됩니다. 다중 스레드 스케일링을 달성하기 위해 게임에 사용 가능한 지연된 컨텍스트가 있습니다. Direct3D 11의 지연된 컨텍스트는 하드웨어에 완벽하게 매핑되지 않으므로 상대적으로 적은 작업을 수행할 수 있습니다.

Direct3D 12에서는 GPU에서 특정 워크로드를 실행하는 데 필요한 전체 정보를 포함하는 명령 목록을 기반으로 한 작업 제출을 위한 새로운 모델이 도입됩니다. 각 새로운 명령 목록에는 사용할 PSO, 필요한 텍스처 및 버퍼 리소스, 모든 그리기 호출에 대한 인수와 같은 정보가 포함되어 있습니다. 각 명령 목록은 자체적으로 포함되어 있고 상태를 상속하지 않기 때문에 드라이버는 모든 필수 GPU 명령을 사전에 자유 스레드 방식으로 컴퓨팅할 수 있습니다. 필요한 유일한 직렬 프로세스는 명령 큐를 통해 GPU에 명령 목록을 최종적으로 제출하는 것입니다.

Direct3D 12에서는 명령 목록 외에도 사전 컴퓨팅 작업의 두 번째 단계인 번들이 도입됩니다. 완전히 자체 포함되어 있고 일반적으로 구성되고 한 번 제출되었다가 폐기되는 명령 목록과 달리, 번들은 재사용이 가능한 상태 상속의 양식을 제공합니다. 예를 들어, 게임에서 서로 다른 텍스처를 가진 두 개의 캐릭터 모델을 그리려고 하는 경우 한 가지 접근법은 동일한 그리기 호출의 두 세트를 사용하여 명령 목록을 기록하는 것입니다. 반면 또 다른 접근법은 단일 캐릭터 모델을 그리는 번들 하나를 “기록”한 다음, 다른 리소스를 사용하여 명령 목록에서 번들을 두 번 “재생”하는 것입니다. 후자의 경우, 디스플레이 드라이버는 적절한 지침을 한 번만 컴퓨팅해야 하며, 명령 목록을 만드는 것은 기본적으로 두 번의 저비용 함수 호출에 해당합니다.

명령 목록 및 번들에 대한 자세한 내용은 Direct3D 12의 작업 제출을 참조하세요.

설명자 힙 및 테이블

Direct3D 11의 리소스 바인딩은 매우 추상적이고 편리하지만, 많은 최신 하드웨어 기능을 충분히 활용하지 못합니다. Direct3D 11에서 게임은 리소스의 view 개체를 만든 다음, 이러한 보기를 파이프라인의 다양한 셰이더 단계에서 여러 slot에 바인딩합니다. 이어서 셰이더는 그리기 시간에 고정된 명시적 바인딩 슬롯에서 데이터를 읽습니다. 이 모델은 게임이 다른 리소스를 사용하여 그릴 때마다 서로 다른 보기를 다른 슬롯에 다시 바인딩하고 그리기를 다시 호출해야 함을 의미합니다. 또한 이 사례는 최신 하드웨어 기능을 충분히 활용하면 제거할 수 있는 오버헤드를 보여줍니다.

Direct3D 12는 바인딩 모델을 최신 하드웨어에 맞게 변경하고 성능을 크게 향상시킵니다. Direct3D 12는 독립 실행형 리소스 보기와 슬롯에 대한 명시적 매핑을 요구하는 대신, 게임이 다양한 리소스 보기를 생성하는 설명자 힙을 제공합니다. 이 스키마는 GPU가 하드웨어 고유 리소스 설명(설명자)을 메모리에 직접 쓸 수 있는 메커니즘을 제공합니다. 특정 그리기 호출에 대해 파이프라인에서 사용할 리소스를 선언하기 위해 게임은 전체 설명자 힙의 하위 범위를 나타내는 설명자 테이블을 하나 이상 지정합니다. 설명자 힙이 적절한 하드웨어별 설명자 데이터로 이미 채워졌으므로 설명자 테이블을 변경하는 것은 매우 저렴한 작업입니다.

Direct3D 12는 설명자 힙과 테이블에서 제공하는 향상된 성능 외에도 리소스가 셰이더에서 동적으로 인덱싱될 수 있도록 하여 전례 없는 유연성과 새로운 렌더링 기술을 제공합니다. 예를 들어, 최신 지연 렌더링 엔진은 일반적으로 중간 g-buffer에 일부 종류의 재료 또는 개체 식별자를 인코딩합니다. Direct3D 11에서 이러한 엔진은 하나의 g-buffer에 너무 많은 재료를 포함하면 최종 렌더링 패스 속도가 현저히 느려질 수 있으므로 너무 많은 재료를 사용하지 않도록 주의해야 합니다. 동적으로 인덱싱 가능한 리소스를 사용하면 천 개의 재료가 포함된 장면을 재료가 10개뿐인 장면만큼 빠르게 완료할 수 있습니다.

설명자 힙 및 테이블에 대한 자세한 내용은 리소스 바인딩Direct3D 11 바인딩 모델과의 차이점을 참조하세요.

Direct3D 11에서 포팅

Direct3D 11에서 포팅은 Direct3D 11에서 Direct3D 12로 포팅에 설명된 관련 프로세스입니다. Direct3D 11, Direct3D 10 및 Direct2D 작업의 옵션 범위도 참조하세요.

Direct3D 12 이해