Direct3D 10의 변경 내용

이 섹션은 Windows 7 이상 및 Windows Server 2008 R2 이상 버전의 Windows 운영 체제에만 적용됩니다.

다음 섹션에서는 Direct3D 11이 Direct3D 10에서 어떻게 변경되었는지 설명합니다.

Kernel-Mode Services에 대한 드라이버 콜백 함수

디바이스별 콜백은 런타임이 사용자 모드 디스플레이 드라이버의 CreateDevice(D3D10) 함수를 호출할 때 Direct3D 버전 11 런타임이 D3DDDI_DEVICECALLBACKS 구조에서 제공하는 함수로, 커널 핸들 및 커널 함수 서명에서 드라이버를 격리합니다. Direct3D 버전 11 런타임은 콜백 의미 체계를 변경하므로, 이전 Direct3D 버전 런타임은 자유 스레드 작업 모드를 지원하지 않는 반면, 콜백 함수의 구현은 자유 스레드 작업 모드를 지원하지 않았습니다. 자유 스레드 모드 작업에 대한 규칙은 드라이버가 자유 스레드 모드(D3D11DDICAPS_FREETHREADED)를 지원한다고 표시한 후에 적용됩니다. 그렇지 않으면 이전의 제한된 규칙이 적용됩니다. 드라이버가 자유 스레드 모드에 대한 지원을 나타내는 방법에 대한 자세한 내용은 스레딩 및 명령 목록을 참조하세요. Direct3D 버전 11에는 여전히 다음과 같은 제한 사항이 있습니다.

  • 한 번에 하나의 스레드만 HCONTEXT에 대해 작동할 수 있습니다. 현재 HCONTEXT를 사용하는 기존 콜백 함수는 pfnPresentCb, pfnRenderCb, pfnEscapeCb, pfnDestroyContextCb, pfnWaitForSynchronizationObjectCbpfnSignalSynchronizationObjectCb입니다. 따라서 둘 이상의 스레드가 이러한 콜백 함수를 호출하고 동일한 HCONTEXT를 사용하는 경우 드라이버는 콜백 함수에 대한 호출을 동기화해야 합니다. 이러한 콜백 함수는 즉각적인 컨텍스트를 조작하는 스레드에서만 호출될 가능성이 높기 때문에 이 요구 사항을 충족하는 것은 매우 자연스러운 일입니다.

  • 드라이버는 해당 드라이버 함수를 호출한 동일한 스레드를 사용하여 다음 드라이버 함수를 호출하는 동안에만 다음 콜백 함수를 호출해야 합니다.

  • 드라이버가 대부분의 리소스 종류에 대한 DestroyResource(D3D10) 함수에서 반환되기 전에 드라이버가 pfnDeallocateCb를 호출할 필요가 없으므로 pfnDeallocateCb 콜백 함수는 특별한 멘션 받을 자격이 있습니다. DestroyResource(D3D10)는 자유 스레드 함수이므로 드라이버는 기존의 즉각적인 컨텍스트 참조가 유지되지 않도록 효율적으로 보장할 수 있을 때까지 개체의 소멸을 연기해야 합니다(즉, 드라이버는 pfnDeallocateCb 전에 pfnRenderCb를 호출해야 함). 이 제한은 공유 리소스 또는 HRESOURCE를 사용하여 hRESOURCE 사용을 pfnAllocateCb로 보완하는 다른 콜백 함수에도 적용됩니다. 그러나 이 제한은 주 복제본에는 적용되지 않습니다. 기본 예외에 대한 자세한 내용은 기본 예외를 참조하세요. 일부 애플리케이션에는 동기 소멸의 모양이 필요할 수 있으므로 드라이버는 Flush(D3D10) 함수를 호출하는 동안 이전에 제거된 공유 리소스에 대해 pfnDeallocateCb를 호출하는지 확인해야 합니다. 또한 드라이버는 Flush(D3D10) 함수를 호출하는 동안 이전에 제거된 개체(파이프라인을 중단하지 않는 개체만)를 정리해야 합니다. 드라이버는 런타임이 Flush(D3D10)를 공식 메커니즘으로 호출하여 이러한 메커니즘이 필요할 수 있는 소수의 애플리케이션에 대해 지연된 소멸된 개체를 정리하도록 해야 합니다. 이 메커니즘에 대한 자세한 내용은 지연된 소멸 및 플러시(D3D10)를 참조하세요. 또한 드라이버는 삭제가 지연된 모든 개체가 완전히 제거된 후 정리 중에 드라이버의 DestroyDevice(D3D10) 함수가 반환되도록 해야 합니다.

Free-Threaded DDI 수정을 허용하는 기능 사용 중단

Direct3D 버전 11의 경우 디스플레이 디바이스의 API 수준 개념과 즉각적인 컨텍스트는 여전히 디스플레이 디바이스의 레거시 개념에 따라 DDI 수준에서 함께 번들로 제공됩니다. 이 디스플레이 디바이스와 즉각적인 컨텍스트의 묶음은 이전 버전 DDI(예: Direct3D 버전 10 DDI)와의 호환성을 최대화하고 여러 버전의 DDI를 통해 여러 버전의 API를 지원할 때 드라이버 변동을 줄입니다. 그러나 디스플레이 디바이스와 즉각적인 컨텍스트를 번들로 묶으면 스레딩 도메인이 매우 명시적이지 않기 때문에 DDI가 더 혼란스러워집니다. 대신, 여러 인터페이스의 스레딩 요구 사항과 해당 인터페이스 내의 함수를 이해하려면 드라이버 개발자가 설명서를 참조해야 합니다.

Direct3D 버전 11 API의 주요 기능은 여러 스레드가 함수 만들기 및 삭제를 동시에 입력할 수 있다는 것입니다. 이러한 기능은 D3D10DDI_DEVICEFUNCS 지정되고 D3D10_1DDI_DEVICEFUNCS 허용되는 함수에 대한 Direct3D 버전 10 DDI 의미 체계로 드라이버가 생성 및 삭제를 위한 함수 테이블 포인터를 교환할 수 있도록 허용하는 것과 호환되지 않습니다. 따라서 드라이버가 create(CreateDevice(D3D10))에 대한 함수 포인터를 다시 전달한 후에는 드라이버가 Direct3D 버전 11 DDI에서 실행되고 드라이버가 DDI 스레딩을 지원하는 동안 이러한 특정 함수 포인터를 수정하여 동작을 변경하려고 시도해서는 안 됩니다. 이 제한은 pfnCreate, pfnOpen, pfnDestroy, pfnCalcPrivatepfnCheck로 시작하는 모든 디바이스 함수에 적용됩니다. 나머지 디바이스 함수는 모두 즉각적인 컨텍스트와 강력하게 연결됩니다. 단일 스레드는 한 번에 직접 컨텍스트를 조작하므로 드라이버가 직접 컨텍스트 함수 테이블 항목을 핫 스왑할 수 있도록 계속 허용하도록 잘 정의됩니다.

pfnRenderCb와 pfnPerformAmortizedProcessingCb 비교

Direct3D 버전 10 API 함수는 Direct3D 런타임의 pfnRenderCb 커널 콜백 함수를 연결하여 분할 상환 처리를 수행했습니다(즉, 모든 API 함수 호출에 대해 특정 작업을 실행하는 대신 드라이버가 많은 API 함수 호출마다 분할 상환 작업을 수행함). API는 일반적으로 이 기회를 사용하여 높은 워터마크를 자르고 지연된 개체 소멸 큐를 플러시합니다.

커널 콜백 함수가 드라이버에 대해 가능한 한 자유 스레드가 될 수 있도록 하기 위해 드라이버가 Direct3D 버전 11 DDI를 지원할 때 Direct3D API는 더 이상 pfnRenderCb 를 사용하지 않습니다. 따라서 Direct3D 버전 11 DDI를 지원하는 드라이버는 드라이버가 직접 컨텍스트(또는 유사한 빈도)에 명령 버퍼를 제출한 후 드라이버 DDI 함수를 입력한 동일한 스레드에서 pfnPerformAmortizedProcessingCb 커널 콜백 함수를 수동으로 호출해야 합니다. 작업은 높은 워터마크를 트리밍해야 하므로 드라이버가 상태 새로 고침 DDI 콜백 함수를 활용할 때 명령 버퍼 프리앰블을 생성하기 전에 이 작업을 수행하는 것이 유리합니다.

또한 드라이버는 API 상각 문제를 인식하고 pfnPerformAmortizedProcessingCb 커널 콜백 함수를 사용하는 빈도의 균형을 유지해야 합니다. 한 가지 극단적인 경우 드라이버로 인해 과도 처리가 발생할 수 있습니다. 예를 들어 드라이버가 항상 pfnPerformAmortizedProcessingCb 를 두 번(백투백)하는 경우 다중 엔진 사용으로 인해 드라이버가 pfnPerformAmortizedProcessingCb를 한 번만 호출하는 것이 더 효율적입니다. 다른 극단적인 경우 드라이버가 프레임 렌더링 디자인이 교대로 인해 pfnPerformAmortizedProcessingCb를 호출하지 않은 경우 드라이버에서 Direct3D API가 전체 프레임에 대한 작업을 수행하도록 허용하지 않을 수 있습니다. 드라이버가 pfnPerformAmortizedProcessingCb 를 자연스럽게 호출하는 것보다 더 자주 호출할 필요가 없습니다. 예를 들어 드라이버가 1밀리초 기간에 pfnPerformAmortizedProcessingCb 를 호출하지 않은 경우 API를 펌핑해야 합니다. 드라이버는 pfnPerformAmortizedProcessingCb를 동반해야 하는 기존 pfnRenderCb 호출 중 하나만 확인하고 당연히 작업의 스레딩 의미 체계를 준수해야 합니다.

명령 목록을 지원하는 드라이버의 경우 해당 드라이버가 공간이 부족할 때마다 지연된 컨텍스트에서 pfnPerformAmortizedProcessingCb 를 호출해야 합니다(모든 즉각적인 컨텍스트 플러시와 유사한 빈도). Direct3D 버전 11 런타임은 적어도 이러한 작업 중에 상위 워터마크를 트리밍할 것으로 예상합니다. pfnRenderCb와 관련된 스레딩 의미 체계가 Direct3D 버전 11에 대해 완화되었으므로 Direct3D 버전 11이 pfnRenderCb를 계속 후크할 수 있도록 하려면 동시성 문제를 해결해야 합니다.

새 DDI 오류 코드

드라이버가 Direct3D 버전 11 API가 없는 유효성 검사에 참여할 수 있도록 D3DDDIERR_APPLICATIONERROR 오류 코드가 만들어집니다. 이전에는 드라이버가 E_INVALIDARG 오류 코드를 반환한 경우 API에서 예외가 발생합니다. 디버그 계층이 있으면 디버깅 출력이 발생하고 드라이버가 내부 오류를 반환했음을 나타냅니다. 디버깅 출력은 드라이버에 버그가 있음을 개발자에게 제안합니다. 드라이버가 D3DDDIERR_APPLICATIONERROR 반환하는 경우 디버그 계층은 애플리케이션이 잘못되었다는 것을 대신 확인합니다.

소급하여 Free-Threaded CalcPrivate DDI 필요

Direct3D 버전 11에서는 Direct3D 버전 10 DDI 함수에서 pfnCalcPrivate 로 시작하는 드라이버 함수를 소급하여 스레드 해제해야 합니다. 이 소급 요구 사항은 드라이버가 DDI 스레딩을 지원하지 않는다고 표시하더라도 항상 pfnCalcPrivate*pfnCalcDeferredContextHandleSize 함수를 스레드 해제하도록 요구하는 Direct3D 버전 11 DDI의 동작과 일치합니다. 이 소급 요구 사항에 대한 자세한 내용은 CalcPrivate DPI를 소급하여 Free-Threaded 필요를 참조하세요.

지연된 소멸 및 플러시 D3D10

이제 모든 삭제 함수가 자유 스레드이므로 Direct3D 런타임은 소멸 중에 명령 버퍼를 플러시할 수 없습니다. 따라서 파기 함수는 드라이버가 즉각적인 컨텍스트를 조작하는 스레드가 더 이상 해당 개체에 종속되지 않도록 할 때까지 개체의 실제 소멸을 연기해야 합니다. 각 개별 직접 컨텍스트 메서드는 동기화를 효율적으로 사용하여 이 소멸 문제를 해결할 수 없습니다. 따라서 드라이버는 명령 버퍼를 플러시할 때만 동기화를 사용해야 합니다. 또한 Direct3D 런타임은 유사한 문제를 처리해야 하는 경우에도 이와 동일한 디자인을 사용합니다.

지연된 소멸의 비준으로 인해 Direct3D 런타임은 지연된 소멸 해결 방법을 허용할 수 없는 애플리케이션이 명시적 메커니즘을 대신 사용한다고 주장합니다. 따라서 드라이버는 Flush(D3D10) 함수를 호출하는 동안(명령 버퍼가 비어 있더라도) 지연된 소멸 큐를 처리하여 이러한 메커니즘이 실제로 작동하는지 확인해야 합니다.

동기 소멸 형식이 필요한 애플리케이션은 필요한 파괴의 중량에 따라 다음 패턴 중 하나를 사용해야 합니다.

  • 애플리케이션이 해당 개체에 대한 모든 종속성(즉, 명령 목록, 뷰, 미들웨어 등)을 해제하도록 한 후 애플리케이션은 다음 패턴을 사용합니다.

    Object::Release(); // Final release
    ImmediateContext::ClearState(); // Remove all ImmediateContext references as well.
    ImmediateContext::Flush(); // Destroy all objects as quickly as possible.
    
  • 다음 패턴은 더 무거운 파괴입니다.

    Object::Release(); // Final release
    ImmediateContext::ClearState(); // Remove all ImmediateContext references as well.
    ImmediateContext::Flush();
    ImmediateContext::End( EventQuery );
    while( S_FALSE == ImmediateContext::GetData( EventQuery ) ) ;
    ImmediateContext::Flush(); // Destroy all objects, completely.
    

기본 예외

주 복제본은 런타임이 드라이버의 CreateResource(D3D11) 함수를 호출할 때 만드는 리소스입니다. 런타임은 D3D11DDIARG_CREATERESOURCE 구조체의 pPrimaryDesc 멤버를 DXGI_DDI_PRIMARY_DESC 구조체에 대한 유효한 포인터로 설정하여 주 데이터베이스를 만듭니 다. 기본 항목에는 Direct3D 10에서 Direct3D 11로의 이전 변경과 관련하여 다음과 같은 주목할 만한 예외가 있습니다.

  • 기본 복제본에 대한 드라이버의 CreateResource(D3D11)DestroyResource(D3D10) 함수는 모두 자유 스레드가 아니며 즉각적인 컨텍스트 스레딩 도메인을 공유합니다. 동시성은 여전히 createResource(D3D11) 및 DestroyResource(D3D10)를 포함하는 pfnCreatepfnDestroy로 시작하는 함수와 함께 존재할 수 있습니다. 그러나 주 복제본에 대한 CreateResource(D3D11)DestroyResource(D3D10) 에서는 동시성이 존재할 수 없습니다. 예를 들어 드라이버는 CreateResource(D3D11) 또는 DestroyResource(D3D10) 함수에 대한 호출이 주 함수에 대한 호출임을 감지하여 함수 호출 기간 동안 컨텍스트 메모리를 안전하게 사용하거나 터치할 수 있는지 확인할 수 있습니다.

  • Direct3D 런타임에서는 기본 소멸을 연기할 수 없으며 드라이버는 드라이버의 DestroyResource(D3D10) 함수 호출 내에서 pfnDeallocateCb 함수를 적절하게 호출해야 합니다.