다음을 통해 공유


비동기 프로그래밍(DirectX 및 C++)

이 항목에서는 DirectX에서 비동기 프로그래밍 및 스레딩을 사용할 때 고려해야 할 다양한 사항에 대해 설명합니다.

비동기 프로그래밍 및 DirectX

DirectX에 대해 배우거나 경험이 있는 경우에도 모든 그래픽 처리 파이프라인을 하나의 스레드에 배치하는 것이 좋습니다. 게임의 지정된 장면에는 비트맵, 셰이더 및 배타적 액세스가 필요한 기타 자산과 같은 공통 리소스가 있습니다. 동일한 리소스를 사용하려면 병렬 스레드에서 이러한 리소스에 대한 액세스를 동기화해야 합니다. 렌더링은 여러 스레드에서 병렬화하기 어려운 프로세스입니다.

그러나 게임이 충분히 복잡하거나 성능을 향상하려는 경우 비동기 프로그래밍을 사용하여 렌더링 파이프라인과 관련이 없는 일부 구성 요소를 병렬화할 수 있습니다. 최신 하드웨어는 여러 코어 및 하이퍼스레딩을 사용하는 CPU를 갖추고 있으며, 앱은 이를 활용해야 합니다! 다음과 같이 Direct3D 디바이스 컨텍스트에 직접 액세스할 필요가 없는 게임의 일부 구성 요소에 비동기 프로그래밍을 사용하여 이를 보장할 수 있습니다.

  • 파일 I/O
  • 물리학
  • AI
  • networking
  • 오디오
  • 컨트롤
  • XAML 기반 UI 구성 요소

앱은 동시에 여러 스레드에서 이러한 구성 요소를 처리할 수 있습니다. 파일 I/O, 특히 자산 로드는 수 메가바이트(또는 수백 메가바이트)의 자산이 로드되거나 스트리밍되는 동안 게임 또는 앱이 대화형 상태일 수 있으므로 비동기 로딩의 이점을 크게 얻을 수 있습니다. 이러한 스레드를 만들고 관리하는 가장 쉬운 방법은 PPLTasks.h에 정의된 동시성 네임스페이스에 포함된 병렬 패턴 라이브러리작업 패턴을 사용하는 것입니다. 병렬 패턴 라이브러리를 사용하면 여러 코어 및 하이퍼스레딩을 사용하는 CPU를 직접 활용하며, 인식된 로드 시간부터 집중적인 CPU 계산 또는 네트워크 처리와 함께 발생하는 히치 및 지연에 이르기까지 모든 것을 개선할 수 있습니다.

참고 UWP(유니버설 Windows 플랫폼) 앱에서 사용자 인터페이스는 전적으로 STA(단일 스레드 아파트)에서 실행됩니다. XAML interop을 사용하여 DirectX 게임에 대한 UI를 만드는 경우 STA를 사용하여 컨트롤에만 액세스할 수 있습니다.

 

Direct3D 디바이스를 사용한 다중 스레딩

디바이스 컨텍스트에 대한 다중 스레딩은 Direct3D 기능 수준 11_0 이상을 지원하는 그래픽 디바이스에서만 사용할 수 있습니다. 그러나 전용 게임 플랫폼과 같은 많은 플랫폼에서 강력한 GPU의 사용을 최대화할 수 있습니다. 가장 간단한 경우 HUD(헤드업 디스플레이) 오버레이의 렌더링을 3D 장면 렌더링 및 프로젝션과 분리하고 두 구성 요소 모두 별도의 병렬 파이프라인을 사용하도록 할 수 있습니다. 두 스레드 모두 동일한 ID3D11DeviceContext를 사용하여 리소스 개체(텍스처, 메시, 셰이더 및 기타 자산)를 만들고 관리해야 하지만, 이는 단일 스레드이며 안전하게 액세스하려면 일종의 동기화 메커니즘(예: 임계 영역)을 구현해야 합니다. 또한 다른 스레드에서 디바이스 컨텍스트에 대한 별도의 명령 목록을 만들 수 있지만(지연된 렌더링의 경우) 동일한 ID3D11DeviceContext 인스턴스에서 해당 명령 목록을 동시에 재생할 수 없습니다.

이제 앱은 다중 스레딩에 안전한 ID3D11Device를 사용하여 리소스 개체를 만들 수도 있습니다. 그렇다면 ID3D11DeviceContext 대신 항상 ID3D11Device를 사용하는 것은 어떨까요? 현재는 일부 그래픽 인터페이스에서 다중 스레딩에 대한 드라이버 지원을 사용하지 못할 수 있습니다. 디바이스를 쿼리하고 다중 스레딩을 지원하는지 확인할 수 있지만, 가장 광범위한 대상 그룹에 도달하려는 경우 리소스 개체 관리를 위해 단일 스레드 ID3D11DeviceContext를 고수할 수 있습니다. 즉, 그래픽 디바이스 드라이버가 다중 스레딩 또는 명령 목록을 지원하지 않는 경우 Direct3D 11은 디바이스 컨텍스트에 대한 동기화된 액세스를 내부적으로 처리하려고 시도합니다. 명령 목록이 지원되지 않는 경우 소프트웨어 구현을 제공합니다. 따라서 다중 스레드 디바이스 컨텍스트 액세스에 대한 드라이버 지원이 부족한 그래픽 인터페이스가 있는 플랫폼에서 실행되는 다중 스레드 코드를 작성할 수 있습니다.

앱이 명령 목록을 처리하고 프레임을 표시하기 위해 별도의 스레드를 지원하는 경우, GPU를 활성 상태로 유지하고 명령 목록을 처리하는 동시에 인식할 수 있는 끊김이나 지연 없이 적시에 프레임을 표시하려고 할 수 있습니다. 이 경우 각 스레드에 별개의 ID3D11DeviceContext를 사용하고 D3D11_RESOURCE_MISC_SHARED 플래그로 리소스를 만들어 텍스처 등의 리소스를 공유할 수 있습니다. 이 시나리오에서는 표시 스레드에서 리소스 개체를 처리한 결과를 표시하기 전에 명령 목록 실행을 완료하려면 처리 스레드에서 ID3D11DeviceContext::Flush를 호출해야 합니다.

지연된 렌더링

지연 렌더링은 다른 시간에 재생할 수 있도록 명령 목록에 그래픽 명령을 기록하며, 추가 스레드에서 렌더링하기 위한 명령을 기록하는 동안 한 스레드에서 렌더링을 지원하도록 설계되었습니다. 이러한 명령이 완료되면 최종 표시 개체(프레임 버퍼, 텍스처 또는 기타 그래픽 출력)를 생성하는 스레드에서 실행할 수 있습니다.

ID3D11Device::CreateDeferredContext를 사용하여 지연 컨텍스트를 생성합니다(즉각적인 컨텍스트를 생성하는 D3D11CreateDevice 또는 D3D11CreateDeviceAndSwapChain 대신). 자세한 내용은 즉각적인 렌더링 및 지연 렌더링을 참조하세요.