Context-Local DDI 핸들 사용
이 섹션은 Windows 7 이상 및 Windows Server 2008 R2 이상 버전의 Windows 운영 체제에만 적용됩니다.
각 개체(예: 리소스, 셰이더 등)에는 컨텍스트 로컬 DDI 핸들이 있습니다.
개체가 지연된 세 컨텍스트와 함께 사용되었다고 가정해 보겠습니다. 이 경우 4개의 핸들은 동일한 개체(지연된 각 컨텍스트에 대한 하나의 핸들 및 직접 컨텍스트에 대한 다른 핸들)를 참조합니다. 각 컨텍스트는 스레드에서 동시에 조작할 수 있으므로 컨텍스트-로컬 핸들은 여러 CPU 스레드가 유사한 메모리(의도적으로 또는 의도치 않게)에 대해 경합하지 않도록 합니다. 또한 컨텍스트-로컬 핸들은 드라이버가 컨텍스트별로 논리적으로 연결된 이 데이터의 대부분을 수정해야 하기 때문에 직관적입니다(예: 개체가 컨텍스트에 의해 바인딩될 수 있는 등).
즉각적인 컨텍스트 핸들과 지연된 컨텍스트 핸들의 구분은 여전히 존재합니다. 특히 직접 컨텍스트 핸들은 할당된 첫 번째 핸들과 삭제된 마지막 핸들이 되도록 보장됩니다. 해당 직접 컨텍스트 핸들은 지연된 각 컨텍스트 핸들을 "여는" 동안 함께 연결하기 위해 제공됩니다. 현재는 디바이스별 DDI 핸들이 있는 개체의 개념이 없습니다(즉, 직접 컨텍스트 핸들 이후에 생성되고 삭제되고 컨텍스트 핸들 생성에 의해서만 참조되는 핸들).
일부 핸들은 다른 핸들과 종속성 관계를 갖습니다(예: 뷰는 해당 리소스에 대한 종속성 포함). 직접 컨텍스트에 대해 존재하는 생성 및 소멸 순서는 지연된 컨텍스트 핸들로도 확장됩니다(즉, 런타임이 해당 리소스에 대한 컨텍스트-로컬 뷰 핸들을 만들기 전에 런타임이 컨텍스트-로컬 리소스 핸들을 만들고 런타임이 해당 리소스에 대한 모든 컨텍스트-로컬 뷰 핸들을 삭제한 후 런타임이 컨텍스트-로컬 리소스 핸들을 삭제함). 런타임이 컨텍스트-로컬 핸들을 만들 때 런타임은 해당 컨텍스트-로컬 종속성 핸들도 제공합니다.
드라이버 데이터 조직
주의가 필요한 드라이버 데이터 organization 대한 몇 가지 우려가 있습니다. Direct3D 버전 10과 마찬가지로 데이터의 적절한 지역성은 API와 드라이버 간의 캐시 누락을 줄일 수 있습니다. 데이터의 적절한 지역성은 캐시 스래싱을 방지할 수도 있습니다. 이 문제는 자주 액세스하는 여러 데이터 조각이 모두 동일한 캐시 인덱스에 resolve 캐시의 결합적으로 소모될 때 발생합니다. DDI는 드라이버가 핸들을 충족하는 데 필요한 메모리 양과 핸들 값을 할당하는 API를 API에 알리는 드라이버에서 이러한 문제가 나타나지 않도록 Direct3D 버전 10부터 설계되었습니다. 그러나 새로운 스레드 관련 문제는 Direct3D 버전 11 기간의 DDI 디자인에 영향을 줍니다.
당연히 컨텍스트-로컬 핸들은 컨텍스트당 개체 데이터를 연결하는 방법을 제공하여 스레드 간의 경합 문제를 방지합니다. 그러나 이러한 데이터는 지연된 각 컨텍스트에 대해 복제되므로 이러한 데이터의 크기가 주요 관심사입니다. 즉, 즉각적인 컨텍스트 핸들과 지연된 컨텍스트 핸들 간에 읽기 전용 데이터를 공유하는 자연 합리화를 제공합니다. 지연된 컨텍스트 핸들을 만드는 동안 핸들 간의 연결을 설정하기 위해 직접 컨텍스트 핸들이 제공됩니다. 그러나 지연된 컨텍스트 핸들에서 벗어난 모든 데이터는 API 데이터로 지역성 이점을 얻을 수 있으며 읽기 전용 데이터에 대한 추가 간접 간접 수준은 지역성 혜택이 읽기 전용 데이터로 확장되지 않도록 방지합니다. 지역 혜택이 데이터 중복을 정당화하는 경우 일부 읽기 전용 데이터를 각 컨텍스트 핸들 지역에 복제할 수 있습니다. 그러나 지연된 각 컨텍스트 핸들을 백업하는 메모리는 해당 데이터가 상대적으로 크고 다른 데이터만큼 자주 액세스하지 않는 경우 핸들에서 인접하지 않은 데이터를 재배치하는 것이 좋습니다. 이상적으로 지연된 각 컨텍스트 핸들과 연결된 데이터 형식은 모두 고주파 데이터입니다. 따라서 데이터가 재배치 필요를 고려할 만큼 크지 않습니다. 당연히 드라이버는 이러한 상충하는 동기의 균형을 유지해야 합니다.
드라이버 데이터 디자인이 Direct3D 버전 10과 효율적으로 호환되지만 구현이 서로 다를 수 없도록 하려면 읽기 전용 데이터가 연속적으로 위치해야 합니다(하지만 이후에도 여전히 분리됨). 드라이버가 이 디자인을 사용하는 경우 드라이버는 즉각적인 컨텍스트 핸들 데이터와 읽기 전용 데이터 간에 캐시 줄 안쪽 여백이 필요하다는 것을 알고 있어야 합니다. 스레드는 각 컨텍스트 핸들 데이터를 자주 조작할 수 있으므로(동시에는 그렇지 않은 경우) 캐시 라인 패딩을 사용하지 않는 경우 직접 컨텍스트 핸들 데이터와 지연된 컨텍스트 핸들 데이터 간에 거짓 공유가 발생합니다. 드라이버 디자인은 컨텍스트 핸들 메모리 영역 간에 포인터가 설정되고 정기적으로 트래버스되는 경우 나타나는 거짓 공유 페널티를 인식해야 합니다.
Direct3D 런타임은 지연된 컨텍스트 로컬 핸들에 다음 Direct3D 11 DDI를 사용합니다.
CheckDeferredContextHandleSizes 함수는 지연된 컨텍스트 핸들의 핸들 데이터를 포함하는 드라이버-프라이빗 메모리 공간의 크기를 확인합니다.
CalcDeferredContextHandleSize 함수는 지연된 컨텍스트의 메모리 영역 크기를 결정합니다.
Direct3D 런타임이 드라이버에 필요한 지연된 컨텍스트 핸들 크기를 검색하려면 이전 DDI 함수를 사용해야 합니다. 직접 컨텍스트에 대한 개체를 만든 직후 런타임은 CalcDeferredContextHandleSize 를 호출하여 드라이버가 이 개체에 대한 지연된 컨텍스트 핸들을 충족하는 데 필요한 스토리지 공간의 양을 드라이버에 쿼리합니다. 그러나 Direct3D API는 액세스되는 고유 핸들 크기 및 해당 값의 수를 결정하여 CLS 메모리 할당자를 조정해야 합니다. 런타임은 드라이버의 CheckDeferredContextHandleSizes 함수를 호출하여 이 정보를 가져옵니다. 따라서 디바이스 인스턴스화 중에 API는 이중 폴링으로 지연된 컨텍스트 핸들 크기의 배열을 요청합니다. 첫 번째 설문 조사는 반환되는 크기 수를 요청하는 반면, 두 번째 폴은 배열을 통과하여 각 크기의 값을 검색합니다. 드라이버는 핸들 형식과 함께 핸들을 충족하는 데 필요한 메모리 양을 나타내야 합니다. 드라이버는 특정 핸들 형식과 연결된 여러 크기를 반환할 수 있습니다. 그러나 드라이버가 CheckDeferredContextHandleSizes 배열에서도 해당 값으로 반환되지 않은 CalcDeferredContextHandleSize 값을 반환하도록 정의되지 않았습니다.
DDI 핸들을 만드는 경우 지연된 컨텍스트에서 메서드 만들기가 사용됩니다. 예를 들어 CreateBlendState(D3D10_1) 및 DestroyBlendState 함수를 검사합니다. HDEVICE는 자연스럽게 적절한 지연된 컨텍스트와 즉각적인 컨텍스트를 가리킵니다. 다른 CONST 구조 포인터는 NULL 입니다(개체에 종속성이 없다고 가정). 및 D3D10DDI_HRT* 핸들은 해당 직접 컨텍스트 개체에 대한 D3D10DDI_H* 핸들입니다.
종속성이 있는 개체(예: 뷰에 해당 리소스에 대한 종속성 관계가 있음)의 경우 종속성 핸들을 제공하는 구조체 포인터는 NULL이 아닙니다. 그러나 구조체의 유일한 유효한 멤버는 종속성 핸들입니다. 반면 나머지 멤버는 0으로 채워집니다. 예를 들어 드라이버의 CreateShaderResourceView(D3D11) 함수 호출에서 D3D11DDIARG_CREATESHADERRESOURCEVIEW 포인터는 런타임이 지연된 컨텍스트에서 이 함수를 호출할 때 NULL이 아닙니다. 이 CreateShaderResourceView(D3D11) 호출에서 런타임은 리소스에 대한 적절한 컨텍스트-로컬 핸들을 D3D11DDIARG_CREATESHADERRESOURCEVIEW hDrvResource 멤버에 할당합니다. 하지만 나머지 D3D11DDIARG_CREATESHADERRESOURCEVIEW 멤버는 0으로 채워집니다.
다음 예제 코드는 Direct3D 런타임이 애플리케이션의 만들기 요청을 변환하고 지연된 컨텍스트를 사용자 모드 표시 드라이버에 대한 호출로 처음 사용하여 즉시 및 지연된 컨텍스트를 만드는 방법을 보여 줍니다. ID3D11Device::CreateTexture2D에 대한 애플리케이션의 호출은 다음 "리소스 만들기" 섹션에서 런타임 코드를 시작합니다. ID3D11Device::CopyResource에 대한 애플리케이션의 호출은 다음 "지연 컨텍스트 리소스 사용" 섹션에서 런타임 코드를 시작합니다.
// Device Create
IC::pfnCheckDeferredContextHandleSizes( hIC, &u, NULL );
pArray = malloc( u * ... );
IC::pfnCheckDeferredContextHandleSizes( hIC, &u, pArray );
// Resource Create
s = IC::pfnCalcPrivateResourceSize( hIC, &Args );
pICRHandle = malloc( s );
IC::pfnCreateResource( hIC, &Args, pICRHandle, hRTResource );
s2 = IC::pfnCalcDeferredContextHandleSize( hIC, D3D10DDI_HT_RESOURCE, pICRHandle );
// Deferred Context Resource Usage
pDCRHandle = malloc( s2 );
DC::pfnCreateResource( hDC, NULL, pDCRHandle, pICRHandle );
pfnSetErrorCb 관련 문제
Create 함수 중 Direct3D 버전 11 스레딩 모델에 이상적인 오류 코드를 반환하는 함수는 없습니다. 모든 만들기 함수는 pfnSetErrorCb 를 사용하여 드라이버에서 오류 코드를 다시 검색합니다. Direct3D 버전 10 드라이버 모델과의 호환성을 최대화하기 위해 오류 코드를 반환하는 새 DDI 만들기 함수가 도입되지 않았습니다. 대신, 드라이버는 생성 함수 중에 pfnSetErrorCb 와 함께 통합 디바이스/즉각적인 컨텍스트 D3D10DDI_HRTCORELAYER 핸들을 계속 사용해야 합니다. 드라이버가 명령 목록을 지원하는 경우 드라이버는 해당 컨텍스트와 연결된 적절한 pfnSetErrorCb 를 사용해야 합니다. 즉, 지연된 컨텍스트 오류는 해당 핸들이 있는 pfnSetErrorCb 에 대한 특정 지연된 컨텍스트 호출로 이동해야 합니다.
지연된 컨텍스트는 DDI 함수를 호출할 때마다 지연된 컨텍스트 메모리 요구가 영구적으로 증가하므로 이전에만 D3DDDIERR_DEVICEREMOVED 허용한 DDI 함수(예: Draw, SetBlendState 등)에서 pfnSetErrorCb 호출을 통해 E_OUTOFMEMORY 반환할 수 있습니다. Direct3D API는 로컬 컨텍스트 제거를 트리거하여 부분적으로 빌드된 명령 목록을 효과적으로 토스아웃하는 이러한 오류 사례를 드라이버에 지원합니다. 애플리케이션은 명령 목록을 기록하고 있는지 계속 확인합니다. 그러나 애플리케이션이 결국 FinishCommandList 함수를 호출하면 FinishCommandList 는 E_OUTOFMEMORY 오류 코드를 반환합니다.