12에서 Direct3D 11

D3D11On12는 개발자가 D3D11 인터페이스와 개체를 사용하여 D3D12 API를 구동할 수 있는 메커니즘입니다. D3D11on12에서는 D3D11(예: D2D 텍스트 및 UI)을 사용하여 작성된 구성 요소가 D3D12 API를 대상으로 작성된 구성 요소와 함께 작동할 수 있습니다. 또한 D3D11on12에서는 앱의 일부는 단순성을 위해 D3D11을 계속 대상으로 하고, 다른 항목은 성능을 위해 D3D12를 대상으로 하면서도 항상 완전하고 정확한 렌더링은 유지함으로써 D3D11에서 D3D12로 애플리케이션을 점진적으로 포팅할 수 있습니다. D3D11On12를 통해 두 API 사이에서 리소스를 공유하고 작업을 동기화하는 interop 기술을 사용하는 것보다 더 간단히 수행할 수 있습니다.

D3D11On12 초기화

D3D11On12 사용을 시작하기 위한 첫 번째 단계는 D3D12 디바이스 및 명령 큐를 만드는 것입니다. 이러한 개체는 초기화 메서드 D3D11On12CreateDevice에 입력으로 제공됩니다. 이 메서드는 가상 드라이버 유형이 D3D_DRIVER_TYPE_11ON12 D3D11 디바이스를 만드는 것으로 생각할 수 있습니다. 여기서 D3D11 드라이버는 개체를 만들고 D3D12 API에 명령 목록을 제출해야 합니다.

D3D11 디바이스와 직접 컨텍스트가 있는 경우 ID3D11On12Device 인터페이스에 대해 디바이스의 QueryInterface를 해제할 수 있습니다. 이것은 D3D11과 D3D12 사이의 interop에 사용되는 기본 인터페이스입니다. D3D11 디바이스 컨텍스트와 D3D12 명령 목록이 모두 동일한 리소스에서 작동하도록 하려면 CreateWrappedResource API를 사용하여 “래핑된 리소스”를 생성해야 합니다. 이 방법은 D3D11에서 이해할 수 있도록 D3D12 리소스를 “승격”합니다. 래핑된 리소스는 AcquireWrappedResourcesReleaseWrappedResources 메서드에 의해 조작되는 속성인 “획득됨” 상태로 시작됩니다.

Example Usage

D3D11On12의 일반적인 사용은 D2D를 사용하여 D3D12 백 버퍼 위에 텍스트나 이미지를 렌더링하는 것입니다. 예시 코드는 D3D11On12 샘플을 참조하세요. 다음은 이렇게 하기 위해 취해야 할 단계의 대략적인 개요입니다.

  • D3D12 디바이스(D3D12CreateDevice) 및 D3D12 스왑 체인(ID3D12CommandQueue가 있는 CreateSwapChain)을 만듭니다.
  • D3D12 디바이스 및 동일한 명령 큐를 입력으로 사용하여 D3D11On12 디바이스를 만듭니다.
  • 스왑 체인 백 버퍼를 검색하고 각각에 대해 래핑된 D3D11 리소스를 만듭니다. 사용된 입력 상태는 D3D12에서 사용한 마지막 방법(예: RENDER_TARGET)이어야 하며 출력 상태는 D3D11이 완료된 후 D3D12에서 사용하는 방식(예: PRESENT)이어야 합니다.
  • D2D를 초기화하고 래핑된 D3D11 리소스를 D2D에 제공하여 렌더링을 준비합니다.

그런 다음, 각 프레임에서 다음을 수행합니다.

  • D3D12 명령 목록을 사용하여 현재 스왑 체인 백 버퍼에 렌더링하고 실행합니다.
  • 현재 백 버퍼의 래핑된 리소스를 획득합니다(AcquireWrappedResources).
  • D2D 렌더링 명령을 실행합니다.
  • 래핑된 리소스를 릴리스합니다(ReleaseWrappedResources).
  • D3D11 직접 컨텍스트를 플러시합니다.
  • 프레젠테이션합니다(IDXGISwapChain1::Present1).

배경

D3D11On12는 체계적으로 작동합니다. 각 D3D11 API 호출은 일반적인 런타임 유효성 검사를 거쳐 드라이버로 전달됩니다. 드라이버 계층에서 특수 11on12 드라이버는 상태를 기록하고 D3D12 명령 목록에 렌더링 작업을 실행합니다. 이러한 명령 목록은 필요에 따라 제출되거나(예: 쿼리 GetData 또는 리소스 Map에서 명령을 플러시해야 할 수도 있음) 플러시에서 요청한 대로 제출된다. 일반적으로 D3D11 개체를 생성하면 해당 D3D12 개체가 생성됩니다. GenerateMips 또는 DrawAuto와 같은 D3D11의 일부 고정 함수 렌더링 작업은 D3D12에서 지원되지 않으므로 D3D11On12는 셰이더 및 추가 리소스를 사용하여 그러한 작업을 에뮬레이트합니다.

interop의 경우, 앱이 만들고 제공한 D3D12 개체와 D3D11On12가 어떻게 상호 작용하는지를 이해하는 것이 중요합니다. 작업이 올바른 순서로 수행되도록 하려면 추가 D3D12 작업을 해당 큐에 제출하기 전에 D3D11 직접 컨텍스트를 플러시해야 합니다. 또한 중요한 점은 D3D11On12에 지정된 큐가 항상 드레이닝할 수 있어야 한다는 점입니다. 즉, D3D11 렌더링 스레드가 무기한 차단하는 경우라도 큐의 모든 대기 시간은 결국 충족되어야 합니다. D3D11On12가 플러시를 삽입하거나 대기할 때 종속되지 않도록 주의하세요. 이는 향후 릴리스에 따라 변경될 수 있습니다. 또한 D3D11On12는 자체적으로 리소스 상태를 추적하고 조작합니다. 상태 전환의 일관성을 보장하는 유일한 방법은 획득/릴리스 API를 사용하여 앱의 요구에 맞게 상태 추적을 조작하는 것입니다.

정리

래핑된 D3D11On12 리소스를 릴리스하려면 두 가지 항목이 다음 순서로 수행되어야 합니다.

  • 리소스의 모든 뷰를 포함하여 리소스에 대한 모든 참조를 릴리스해야 합니다.
  • 지연된 소멸 처리가 수행되어야 합니다. 이 내용이 발생되었는지 확인하는 가장 간단한 방법은 직접 컨텍스트 Flush API를 호출하는 것입니다.

이 두 단계를 모두 완료한 후에는 래핑된 리소스에서 사용한 참조가 릴리스되어야 하며, D3D12 리소스는 D3D12 구성 요소에 의해 독점적으로 소유됩니다. 리소스를 완전히 릴리스하기 전에 GPU가 완료될 때까지 D3D12는 계속해서 기다려야 합니다. 따라서 GPU가 더 이상 리소스를 사용하고 있지 않는다는 것을 이미 확인한 경우 외에는 위의 두 단계를 수행하기 전에 리소스에 대한 참조를 유지해야 합니다.

D3D11On12에 의해 생성된 다른 모든 리소스 또는 개체는 GPU가 사용을 마치면 D3D11의 지연된 소멸 메커니즘을 사용하여 적절한 시점에 정리됩니다. 그러나 GPU가 아직 실행 중일 때 D3D11On12 디바이스 자체를 릴리스하려고 시도하면 GPU가 완료될 때까지 소멸이 차단될 수 있습니다.

제한 사항

D3D11On12 계층은 D3D11 API의 매우 큰 하위 세트를 구현하지만, 구현 시 잘못된 렌더링을 유발할 수 있는 버그 외에도 몇 가지 알려진 차이점이 있습니다.

Windows 10 버전 1809(10.0; 빌드 17763)를 기준으로, D3D11On12가 셰이더 모델 6.0 이상을 지원하는 드라이버에서 실행되는 경우 인터페이스를 사용하는 셰이더를 실행할 수 있습니다. 이전 버전의 Windows에서는 셰이더 인터페이스 기능이 D3D11On12에서 구현되지 않았으며, 이 기능을 사용하려고 시도하면 오류와 디버그 메시지가 발생됩니다.

Windows 10 버전 1803(10.0; 빌드 17134)을 기준으로, 스왑 체인이 D3D11On12 디바이스에서 지원됩니다. 이전 버전의 Windows에서는 지원되지 않습니다.

D3D11On12는 성능을 위해 최적화되지 않았습니다. GPU 오버헤드가 최소한인 표준 D3D11 드라이버와 비교해서 CPU 오버헤드가 조정될 가능성이 높으며, 메모리 오버헤드가 상당하다고 알려져 있습니다. 따라서 복잡한 3D 장면에는 D3D11On12를 사용하지 않는 것이 좋습니다. 대신 단순 장면 또는 2D 렌더링에 사용하는 것이 좋습니다.

API

11on12 계층을 만드는 API는 11on12 참조에 설명되어 있습니다.

D3D11on12를 사용한 D2D 연습

Direct3D 12 이해

Direct3D 11, Direct3D 10 및 Direct2D 작업