Direct3D 9Ex 개선 사항
이 항목에서는 대칭 이동 모드 프레젠테이션에 대한 Windows 7의 추가 지원과 Direct3D 9Ex 및 데스크톱 창 관리자의 관련 현재 통계에 대해 설명합니다. 대상 애플리케이션에는 비디오 또는 프레임 속도 기반 프레젠테이션 애플리케이션이 포함됩니다. Direct3D 9Ex 대칭 이동 모드를 사용하는 애플리케이션은 DWM을 사용할 때 시스템 리소스 부하를 줄입니다. Flip Mode Present와 관련된 향상된 통계를 제시하면 Direct3D 9Ex 애플리케이션이 실시간 피드백 및 수정 메커니즘을 제공하여 프레젠테이션 속도를 더 잘 제어할 수 있습니다. 샘플 리소스에 대한 자세한 설명 및 포인터가 포함됩니다.
이 항목에는 다음과 같은 섹션이 포함되어 있습니다.
- Windows 7용 Direct3D 9Ex의 향상된 기능
- Direct3D 9EX 대칭 이동 모드 프레젠테이션
- 프로그래밍 모델 및 API
- Direct3D 9Ex 대칭 이동 모델 및 프레젠테이션 통계 샘플 연습
- Direct3D 9Ex 개선에 대한 결론
- 작업 호출
- 관련 항목
Windows 7용 Direct3D 9Ex의 향상된 기능
Direct3D 9Ex의 대칭 이동 모드 프레젠테이션은 렌더링된 이미지를 구성을 위해 Windows 7 DWM(데스크톱 창 관리자)에 효율적으로 전달하는 Direct3D 9Ex의 이미지를 표시하는 향상된 모드입니다. Windows Vista부터 DWM은 전체 데스크톱을 구성합니다. DWM을 사용하도록 설정하면 창 모드 애플리케이션은 Blt Mode Present to DWM(또는 Blt Model)이라는 메서드를 사용하여 데스크톱에 콘텐츠를 표시합니다. Blt 모델에서 DWM은 데스크톱 컴퍼지션을 위해 Direct3D 9Ex 렌더링된 표면의 복사본을 유지 관리합니다. 애플리케이션이 업데이트되면 새 콘텐츠가 Blt를 통해 DWM 화면에 복사됩니다. Direct3D 및 GDI 콘텐츠를 포함하는 애플리케이션의 경우 GDI 데이터도 DWM 화면에 복사됩니다.
Windows 7에서 사용할 수 있는 대칭 이동 모드 프레젠테이션에서 DWM(또는 대칭 이동 모델)은 기본적으로 창 모드 애플리케이션과 DWM 간에 애플리케이션 화면의 핸들을 전달할 수 있도록 하는 새로운 프레젠테이션 방법입니다. Flip Model은 리소스 저장 외에도 향상된 현재 통계를 지원합니다.
프레젠테이션 통계는 애플리케이션이 비디오 및 오디오 스트림을 동기화하고 비디오 재생 결함에서 복구하는 데 사용할 수 있는 프레임 타이밍 정보입니다. 현재 통계의 프레임 타이밍 정보를 통해 애플리케이션은 보다 원활한 프레젠테이션을 위해 비디오 프레임의 프레젠테이션 속도를 조정할 수 있습니다. DWM이 데스크톱 컴퍼지션을 위해 프레임 표면의 해당 복사본을 유지 관리하는 Windows Vista에서 애플리케이션은 DWM에서 제공하는 현재 통계를 사용할 수 있습니다. 현재 통계를 가져오는 이 방법은 기존 애플리케이션에 대해 Windows 7에서 계속 사용할 수 있습니다.
Windows 7에서 대칭 이동 모델을 채택하는 Direct3D 9Ex 기반 애플리케이션은 D3D9Ex API를 사용하여 현재 통계를 가져와야 합니다. DWM을 사용하도록 설정하면 창 모드 및 전체 화면 전용 모드 Direct3D 9Ex 애플리케이션에서 대칭 이동 모델을 사용할 때 동일한 현재 통계 정보를 기대할 수 있습니다. Direct3D 9Ex Flip Model 프레젠테이션 통계를 사용하면 애플리케이션이 프레임이 화면에 표시된 후가 아니라 실시간으로 현재 통계를 쿼리할 수 있습니다. 창 모드 대칭 이동-모델 사용 애플리케이션에 대해 전체 화면 애플리케이션과 동일한 현재 통계 정보를 사용할 수 있습니다. D3D9Ex API에 추가된 플래그를 사용하면 Flip Model 애플리케이션이 프레젠테이션 시간에 늦은 프레임을 효과적으로 삭제할 수 있습니다.
Direct3D 9Ex 대칭 이동 모델은 Windows 7을 대상으로 하는 새로운 비디오 또는 프레임 속도 기반 프레젠테이션 애플리케이션에서 사용해야 합니다. DWM과 Direct3D 9Ex 런타임 간의 동기화로 인해 대칭 이동 모델을 사용하는 애플리케이션은 원활한 프레젠테이션을 위해 2~4개의 백버퍼를 지정해야 합니다. 현재 통계 정보를 사용하는 애플리케이션은 Flip Model을 사용하도록 설정된 현재 통계 향상 기능을 사용하여 이점을 얻을 수 있습니다.
Direct3D 9EX 대칭 이동 모드 프레젠테이션
Direct3D 9Ex 대칭 이동 모드 프레젠테이션의 성능 향상은 DWM이 켜지고 애플리케이션이 전체 화면 전용 모드가 아닌 창 모드에 있을 때 시스템에서 중요합니다. 다음 표와 그림에서는 대칭 이동 모델과 기본 사용량 Blt 모델을 선택하는 창이 있는 애플리케이션의 메모리 대역폭 사용량 및 시스템 읽기 및 쓰기를 간소화한 비교를 보여 줍니다.
DWM에 있는 Blt 모드 | DWM에 있는 D3D9Ex 대칭 이동 모드 |
---|---|
1. 애플리케이션이 프레임을 업데이트합니다(쓰기). |
1. 애플리케이션이 프레임을 업데이트합니다(쓰기). |
2. Direct3D 런타임은 표면 콘텐츠를 DWM 리디렉션 화면에 복사합니다(읽기, 쓰기). |
2. Direct3D 런타임이 애플리케이션 화면을 DWM에 전달합니다. |
3. 공유 표면 복사가 완료되면 DWM은 애플리케이션 화면을 화면에 렌더링합니다(읽기, 쓰기). |
3. DWM은 애플리케이션 화면을 화면에 렌더링합니다(읽기, 쓰기). |
대칭 이동 모드 프레젠테이션은 DWM의 창 프레임 컴퍼지션에 대한 Direct3D 런타임의 읽기 및 쓰기 수를 줄여 시스템 메모리 사용량을 줄입니다. 이렇게 하면 시스템 전원 사용량과 전체 메모리 사용량이 줄어듭니다.
애플리케이션은 응용 프로그램이 창 모드인지 아니면 전체 화면 전용 모드인지에 관계없이 DWM이 켜지면 Direct3D 9Ex 대칭 이동 모드에서 향상된 통계 기능을 활용할 수 있습니다.
프로그래밍 모델 및 API
Windows 7에서 Direct3D 9Ex API를 사용하는 새로운 비디오 또는 프레임 속도 측정 애플리케이션은 Windows 7에서 실행할 때 대칭 이동 모드 프레젠테이션에서 제공하는 향상된 프레젠테이션과 메모리 및 전원 절약을 활용할 수 있습니다. (이전 Windows 버전에서 실행하는 경우 Direct3D 런타임은 기본적으로 애플리케이션을 Blt 모드 Present로 설정합니다.)
대칭 이동 모드 프레젠테이션에는 DWM이 켜질 때 애플리케이션이 실시간 프레젠테이션 통계 피드백 및 수정 메커니즘을 활용할 수 있습니다. 그러나 대칭 이동 모드를 사용하는 애플리케이션은 동시 GDI API 렌더링을 사용할 때 제한 사항을 알고 있어야 합니다.
기존 애플리케이션을 수정하여 새로 개발된 애플리케이션과 동일한 이점 및 주의 사항과 함께 대칭 이동 모드 프레젠테이션을 활용할 수 있습니다.
Direct3D 9Ex 대칭 이동 모델에 옵트인하는 방법
Windows 7을 대상으로 하는 Direct3D 9Ex 애플리케이션은 D3DSWAPEFFECT_FLIPEX 열거형 값으로 스왑 체인을 만들어 대칭 이동 모델을 옵트인할 수 있습니다. 대칭 이동 모델을 옵트인하기 위해 애플리케이션은 D3DPRESENT_PARAMETERS 구조를 지정한 다음 IDirect3D9Ex::CreateDeviceEx API를 호출할 때 이 구조체에 대한 포인터를 전달합니다. 이 섹션에서는 Windows 7을 대상으로 하는 애플리케이션에서 IDirect3D9Ex::CreateDeviceEx를 사용하여 대칭 이동 모델을 선택하는 방법을 설명합니다. IDirect3D9Ex::CreateDeviceEx API에 대한 자세한 내용은 MSDN의 IDirect3D9Ex::CreateDeviceEx를 참조하세요.
편의를 위해 여기서는 D3DPRESENT_PARAMETERS 및 IDirect3D9Ex::CreateDeviceEx 구문이 반복됩니다.
HRESULT CreateDeviceEx(
UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pPresentationParameters,
D3DDISPLAYMODEEX *pFullscreenDisplayMode,
IDirect3DDevice9Ex **ppReturnedDeviceInterface
);
typedef struct D3DPRESENT_PARAMETERS {
UINT BackBufferWidth, BackBufferHeight;
D3DFORMAT BackBufferFormat;
UINT BackBufferCount;
D3DMULTISAMPLE_TYPE MultiSampleType;
DWORD MultiSampleQuality;
D3DSWAPEFFECT SwapEffect;
HWND hDeviceWindow;
BOOL Windowed;
BOOL EnableAutoDepthStencil;
D3DFORMAT AutoDepthStencilFormat;
DWORD Flags;
UINT FullScreen_RefreshRateInHz;
UINT PresentationInterval;
} D3DPRESENT_PARAMETERS, *LPD3DPRESENT_PARAMETERS;
Windows 7용 Direct3D 9Ex 애플리케이션을 수정하여 대칭 이동 모델을 옵트인하는 경우 지정된 D3DPRESENT_PARAMETERS 멤버에 대해 다음 항목을 고려해야 합니다.
-
BackBufferCount
-
(Windows 7에만 해당)
SwapEffect가 새 D3DSWAPEFFECT_FLIPEX 스왑 체인 효과 형식으로 설정된 경우 이전 Present 버퍼가 DWM에서 해제될 때까지 대기한 결과로 애플리케이션 성능 저하를 방지하기 위해 백 버퍼 수가 2보다 크거나 같아야 합니다.
또한 애플리케이션에서 D3DSWAPEFFECT_FLIPEX 연결된 현재 통계를 사용하는 경우 백 버퍼 수를 2에서 4로 설정하는 것이 좋습니다.
Windows Vista 또는 이전 운영 체제 버전에서 D3DSWAPEFFECT_FLIPEX 사용하면 CreateDeviceEx에서 실패가 반환됩니다.
-
SwapEffect
-
(Windows 7에만 해당)
새 D3DSWAPEFFECT_FLIPEX 스왑 체인 효과 유형은 애플리케이션이 DWM에 대칭 이동 모드 프레젠테이션을 채택하는 시기를 지정합니다. 이를 통해 애플리케이션에서 메모리 및 전원을 보다 효율적으로 사용할 수 있으며, 애플리케이션이 창 모드에서 전체 화면 표시 통계를 활용할 수 있습니다. 전체 화면 애플리케이션 동작은 영향을 받지 않습니다. Windowed가 TRUE로 설정되고 SwapEffect가 D3DSWAPEFFECT_FLIPEX 설정되면 런타임은 하나의 추가 백 버퍼를 만들고 프레젠테이션 시 프런트 버퍼가 되는 버퍼에 속하는 핸들을 회전합니다.
-
Flags
-
(Windows 7에만 해당)
SwapEffect를 새 D3DSWAPEFFECT_FLIPEX 스왑 체인 효과 유형으로 설정하면 D3DPRESENTFLAG_LOCKABLE_BACKBUFFER 플래그를 설정할 수 없습니다.
Direct3D 9Ex 대칭 이동 모델 애플리케이션에 대한 디자인 지침
다음 섹션의 지침을 사용하여 Direct3D 9Ex Flip Model 애플리케이션을 디자인합니다.
Blt 모드에서 별도의 HWND에 있는 대칭 이동 모드 사용
애플리케이션은 Blt Mode Present Direct3D 9Ex, 다른 버전의 Direct3D 또는 GDI를 포함하여 다른 API의 대상이 아닌 HWND에 Direct3D 9Ex 대칭 이동 모드를 사용해야 합니다. 대칭 이동 모드 프레젠테이션을 사용하여 자식 창에 프레젠테이션할 수 있습니다. 즉, 애플리케이션은 다음 그림과 같이 동일한 HWND에서 Blt 모델과 혼합되지 않은 경우 대칭 이동 모델을 사용할 수 있습니다.
Blt Model은 표면의 추가 복사본을 유지 관리하므로 Direct3D 및 GDI의 증분 업데이트를 통해 GDI 및 기타 Direct3D 콘텐츠를 동일한 HWND에 추가할 수 있습니다. 대칭 이동 모델을 사용하면 DWM에 전달되는 D3DSWAPEFFECT_FLIPEX 스왑 체인의 Direct3D 9Ex 콘텐츠만 표시됩니다. 다음 그림과 같이 다른 모든 Blt Model Direct3D 또는 GDI 콘텐츠 업데이트는 무시됩니다.
따라서 Direct3D 9Ex 대칭 이동 모델만 전체 HWND로 렌더링되는 스왑 체인 버퍼 표면에 대해 대칭 이동 모델을 사용하도록 설정해야 합니다.
GDI의 ScrollWindow 또는 ScrollWindowEx에서 대칭 이동 모델을 사용하지 마세요.
일부 Direct3D 9Ex 애플리케이션은 GDI의 ScrollWindow 또는 ScrollWindowEx 함수를 사용하여 사용자 스크롤 이벤트가 트리거될 때 창 콘텐츠를 업데이트합니다. ScrollWindow 및 ScrollWindowEx는 창이 스크롤될 때 화면에서 창 내용의 Blts를 수행합니다. 이러한 함수에는 GDI 및 Direct3D 9Ex 콘텐츠에 대한 Blt 모델 업데이트도 필요합니다. 애플리케이션이 창 모드이고 DWM을 사용하는 경우 두 함수 중 하나를 사용하는 애플리케이션이 화면에 스크롤되는 표시되는 창 내용을 반드시 표시하지는 않습니다. 애플리케이션에서 GDI의 ScrollWindow 및 ScrollWindowEx API를 사용하지 않고 스크롤에 대한 응답으로 화면에서 해당 콘텐츠를 다시 그리는 것이 좋습니다.
HWND당 하나의 D3DSWAPEFFECT_FLIPEX 스왑 체인 사용
대칭 이동 모델을 사용하는 애플리케이션은 동일한 HWND를 대상으로 하는 여러 대칭 이동 모델 스왑 체인을 사용하면 안 됩니다.
Direct3D 9Ex 대칭 이동 모델 애플리케이션의 프레임 동기화
현재 통계는 미디어 애플리케이션이 비디오 및 오디오 스트림을 동기화하고 비디오 재생 결함에서 복구하는 데 사용하는 프레임 타이밍 정보입니다. 현재 통계 가용성을 사용하도록 설정하려면 Direct3D 9Ex 애플리케이션은 애플리케이션이 IDirect3D9Ex::CreateDeviceEx에 전달하는 BehaviorFlags 매개 변수에 D3DCREATE_ENABLE_PRESENTSTATS 디바이스 동작 플래그가 포함되어 있는지 확인해야 합니다.
편의를 위해 여기서는 IDirect3D9Ex::CreateDeviceEx 구문이 반복됩니다.
HRESULT CreateDeviceEx(
UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pPresentationParameters,
D3DDISPLAYMODEEX *pFullscreenDisplayMode,
IDirect3DDevice9Ex **ppReturnedDeviceInterface
);
Direct3D 9Ex 대칭 이동 모델은 D3DPRESENT_INTERVAL_IMMEDIATE 프레젠테이션 플래그 동작을 적용하는 D3DPRESENT_FORCEIMMEDIATE 프레젠테이션 플래그를 추가합니다. Direct3D 9Ex 애플리케이션은 다음과 같이 애플리케이션이 IDirect3DDevice9Ex::P resentEx에 전달하는 dwFlags 매개 변수에 이러한 프레젠테이션 플래그를 지정합니다.
HRESULT PresentEx(
CONST RECT *pSourceRect,
CONST RECT *pDestRect,
HWND hDestWindowOverride,
CONST RGNDATA *pDirtyRegion,
DWORD dwFlags
);
Windows 7용 Direct3D 9Ex 애플리케이션을 수정하는 경우 지정된 D3DPRESENT 프레젠테이션 플래그에 대한 다음 정보를 고려해야 합니다.
-
이 플래그는 전체 화면 모드 또는
(Windows 7에만 해당)
애플리케이션이 CreateDeviceEx 호출에서 D3DSWAPEFFECT_FLIPEX D3DPRESENT_PARAMETERS SwapEffect 멤버를 설정하는 경우
-
(Windows 7에만 해당)
이 플래그는 애플리케이션이 CreateDeviceEx 호출에서 D3DPRESENT_PARAMETERS SwapEffect 멤버를 D3DSWAPEFFECT_FLIPEX 설정하는 경우에만 지정할 수 있습니다. 애플리케이션은 이 플래그를 사용하여 DWM Present 큐에서 나중에 여러 프레임으로 표면을 즉시 업데이트하고 기본적으로 중간 프레임을 건너뛸 수 있습니다.
Windowed FlipEx 지원 애플리케이션은 이 플래그를 사용하여 나중에 DWM Present 큐에 있는 프레임으로 표면을 즉시 업데이트하고 중간 프레임을 건너뛸 수 있습니다. 이는 늦게 감지된 프레임을 삭제하고 컴퍼지션 시간에 후속 프레임을 표시하려는 미디어 애플리케이션에 특히 유용합니다. 이 플래그를 잘못 지정하면 IDirect3DDevice9Ex::P resentEx 에서 잘못된 매개 변수 오류를 반환합니다.
현재 통계 정보를 얻기 위해 애플리케이션은 IDirect3DSwapChain9Ex::GetPresentStatistics API를 호출하여 D3DPRESENTSTATS 구조를 가져옵니다.
D3DPRESENTSTATS 구조에는 IDirect3DDevice9Ex::P resentEx 호출에 대한 통계가 포함됩니다. D3DCREATE_ENABLE_PRESENTSTATS 플래그와 함께 IDirect3D9Ex::CreateDeviceEx 호출을 사용하여 디바이스를 만들어야 합니다. 그렇지 않으면 GetPresentStatistics에서 반환된 데이터는 정의되지 않습니다. Flip-Model 지원 Direct3D 9Ex 스왑 체인은 창 모드와 전체 화면 모드 모두에서 현재 통계 정보를 제공합니다.
창 모드의 Blt-Model 지원 Direct3D 9Ex 스왑 체인의 경우 모든 D3DPRESENTSTATS 구조체 값은 0이 됩니다.
FlipEx 현재 통계의 경우 GetPresentStatistics는 다음과 같은 상황에서 D3DERR_PRESENT_STATISTICS_DISJOINT 반환합니다.
- 시퀀스의 시작을 나타내는 GetPresentStatistics에 대한 첫 번째 호출
- DWM을 켜기에서 끄기로 전환
- 모드 변경: 창 모드에서 전체 화면으로 또는 전체 화면으로 전환
편의를 위해 GetPresentStatistics의 구문은 여기에서 반복됩니다.
HRESULT GetPresentStatistics(
D3DPRESENTSTATS * pPresentationStatistics
);
IDirect3DSwapChain9Ex::GetLastPresentCount 메서드는 스왑 체인과 연결된 디스플레이 디바이스에서 마지막으로 성공한 Present 호출의 현재 ID인 마지막 PresentCount를 반환합니다. 이 Present ID는 D3DPRESENTSTATS 구조체의 PresentCount 멤버 값입니다. Blt-Model 지원 Direct3D 9Ex 스왑 체인의 경우 창 모드에서는 모든 D3DPRESENTSTATS 구조체 값이 0이 됩니다.
편의를 위해 여기서는 IDirect3DSwapChain9Ex::GetLastPresentCount의 구문이 반복됩니다.
HRESULT GetLastPresentCount(
UINT * pLastPresentCount
);
Windows 7용 Direct3D 9Ex 애플리케이션을 수정하는 경우 D3DPRESENTSTATS 구조에 대한 다음 정보를 고려해야 합니다.
- GetLastPresentCount가 반환하는 PresentCount 값은 dwFlags 매개 변수에 지정된 D3DPRESENT_DONOTWAIT PresentEx 호출이 실패를 반환할 때 업데이트되지 않습니다.
- D3DPRESENT_DONOTFLIP PresentEx를 호출하면 GetPresentStatistics 호출이 성공하지만 애플리케이션이 창 모드에 있을 때 업데이트된 D3DPRESENTSTATS 구조를 반환하지 않습니다.
- D3DPRESENTSTATS PresentRefreshCount 및 SyncRefreshCount:
- PresentRefreshCount는 애플리케이션이 모든 vsync에 표시되면 SyncRefreshCount와 같습니다.
- SyncRefreshCount는 현재가 제출될 때 vsync 간격으로 가져오며 SyncQPCTime 은 vsync 간격과 연결된 대략적인 시간입니다.
typedef struct _D3DPRESENTSTATS {
UINT PresentCount;
UINT PresentRefreshCount;
UINT SyncRefreshCount;
LARGE_INTEGER SyncQPCTime;
LARGE_INTEGER SyncGPUTime;
} D3DPRESENTSTATS;
DWM이 꺼져 있을 때 창이 있는 애플리케이션에 대한 프레임 동기화
DWM이 꺼져 있으면 창이 있는 애플리케이션은 대칭 이동 체인을 거치지 않고 모니터 화면에 직접 표시됩니다. Windows Vista에서는 DWM이 꺼져 있을 때 창이 있는 애플리케이션에 대한 프레임 통계 정보를 가져올 수 없습니다. 애플리케이션이 DWM을 인식할 필요가 없는 API를 유지하기 위해 Windows 7은 DWM이 꺼져 있을 때 창이 있는 애플리케이션에 대한 프레임 통계 정보를 반환합니다. DWM이 꺼져 있을 때 반환되는 프레임 통계는 예측에만 해당합니다.
Direct3D 9Ex 대칭 이동 모델 및 프레젠테이션 통계 샘플 연습
Direct3D 9Ex 샘플에 대해 FlipEx 프레젠테이션을 옵트인하려면
- 샘플 애플리케이션이 Windows 7 이상 운영 체제 버전에서 실행되고 있는지 확인합니다.
- CreateDeviceEx 호출에서 D3DPRESENT_PARAMETERS SwapEffect 멤버를 D3DSWAPEFFECT_FLIPEX 설정합니다.
OSVERSIONINFO version;
ZeroMemory(&version, sizeof(version));
version.dwOSVersionInfoSize = sizeof(version);
GetVersionEx(&version);
// Sample would run only on Win7 or higher
// Flip Model present and its associated present statistics behavior are only available on Windows 7 or higher operating system
bool bIsWin7 = (version.dwMajorVersion > 6) ||
((version.dwMajorVersion == 6) && (version.dwMinorVersion >= 1));
if (!bIsWin7)
{
MessageBox(NULL, L"This sample requires Windows 7 or higher", NULL, MB_OK);
return 0;
}
또한 Direct3D 9Ex 샘플에 대한 FlipEx 관련 프레젠테이션 통계를 옵트인하려면
- CreateDeviceEx의 BehaviorFlags 매개 변수에서 D3DCREATE_ENABLE_PRESENTSTATS 설정합니다.
// Set up the structure used to create the D3DDevice
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_FLIPEX; // Opts into Flip Model present for D3D9Ex swapchain
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = 256;
d3dpp.BackBufferHeight = 256;
d3dpp.BackBufferCount = QUEUE_SIZE;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
g_iWidth = d3dpp.BackBufferWidth;
g_iHeight = d3dpp.BackBufferHeight;
// Create the D3DDevice with present statistics enabled - set D3DCREATE_ENABLE_PRESENTSTATS for behaviorFlags parameter
if(FAILED(g_pD3D->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_ENABLE_PRESENTSTATS,
&d3dpp, NULL, &g_pd3dDevice)))
{
return E_FAIL;
}
방지하려면 결함에서 검색 및 복구
큐 프레젠테이션 호출: 권장 백 버퍼 수는 2에서 4까지입니다.
Direct3D 9Ex 샘플은 암시적 백버퍼를 추가합니다. 실제 Present 큐 길이는 백버퍼 수 + 1입니다.
성공적으로 제출된 Present의 현재 ID(PresentCount) 및 연결된 계산/예상 PresentRefreshCount를 모두 저장할 도우미 Present 큐 구조를 만듭니다.
결함 발생을 감지하려면 다음을 수행합니다.
- GetPresentStatistics를 호출 합니다.
- 현재 통계를 얻은 프레임의 현재 ID(PresentCount) 및 vsync 개수(PresentRefreshCount)를 가져옵니다.
- Present ID와 연결된 예상 PresentRefreshCount(샘플 코드의 TargetRefresh)를 검색합니다.
- 실제 PresentRefreshCount가 예상보다 늦으면 결함이 발생했습니다.
결함에서 복구하려면 다음을 수행합니다.
- 건너뛸 프레임 수를 계산합니다(샘플 코드에서 iImmediates 변수 g_).
- 건너뛴 프레임에 간격 D3DPRESENT_FORCEIMMEDIATE 표시합니다.
결함 검색 및 복구에 대한 고려 사항
Glitch 복구는 N(샘플 코드의 g_iQueueDelay 변수)을 사용합니다. 여기서 N(g_iQueueDelay)은 present 큐의 길이를 더한 g_iImmediates 같습니다.
- 프레젠테이션 간격 D3DPRESENT_FORCEIMMEDIATE 있는 프레임 건너뛰기 및 추가
- 처리해야 하는 큐에 대기 중인 프레젠테이션
샘플에서 결함 길이(GLITCH_RECOVERY_LIMIT)로 제한을 설정합니다. 샘플 애플리케이션이 너무 긴 결함(즉, 60Hz 모니터에서 1초 또는 60 vsyncs)에서 복구할 수 없는 경우 간헐적인 애니메이션을 넘어 프레젠테이션 도우미 큐를 다시 설정합니다.
VOID Render()
{
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
g_pd3dDevice->BeginScene();
// Compute new animation parameters for time and frame based animations
// Time-based is a difference between base and current SyncRefreshCount
g_aTimeBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_LastSyncRefreshCount - g_SyncRefreshCount;
// Frame-based is incrementing frame value
g_aFrameBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_iFrameNumber;
RenderBlurredMesh(TRUE); // Time-based
RenderBlurredMesh(FALSE); // Frame-based
g_iBlurHistoryCounter = (g_iBlurHistoryCounter + 1) % BLUR_FRAMES;
DrawText();
g_pd3dDevice->EndScene();
// Performs glitch recovery if glitch was detected
if (g_bGlitchRecovery && (g_iImmediates > 0))
{
// If we have present immediates queued as a result of glitch detected, issue forceimmediate Presents for glitch recovery
g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, D3DPRESENT_FORCEIMMEDIATE);
g_iImmediates--;
g_iShowingGlitchRecovery = MESSAGE_SHOW;
}
// Otherwise, Present normally
else
{
g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, 0);
}
// Add to helper Present queue: PresentID + expected present refresh count of last submitted Present
UINT PresentCount;
g_pd3dSwapChain->GetLastPresentCount(&PresentCount);
g_Queue.QueueFrame(PresentCount, g_TargetRefreshCount);
// QueueDelay specifies # Present calls to be processed before another glitch recovery attempt
if (g_iQueueDelay > 0)
{
g_iQueueDelay--;
}
if (g_bGlitchRecovery)
{
// Additional DONOTFLIP presents for frame conversions, which basically follows the same logic, but without rendering
for (DWORD i = 0; i < g_iDoNotFlipNum; i++)
{
if (g_TargetRefreshCount != -1)
{
g_TargetRefreshCount++;
g_iFrameNumber++;
g_aTimeBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_LastSyncRefreshCount - g_SyncRefreshCount;
g_aFrameBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_iFrameNumber;
g_iBlurHistoryCounter = (g_iBlurHistoryCounter + 1) % BLUR_FRAMES;
}
if (g_iImmediates > 0)
{
g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, D3DPRESENT_FORCEIMMEDIATE | D3DPRESENT_DONOTFLIP);
g_iImmediates--;
}
else
{
g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, D3DPRESENT_DONOTFLIP);
}
UINT PresentCount;
g_pd3dSwapChain->GetLastPresentCount(&PresentCount);
g_Queue.QueueFrame(PresentCount, g_TargetRefreshCount);
if (g_iQueueDelay > 0)
{
g_iQueueDelay--;
}
}
}
// Check Present Stats info for glitch detection
D3DPRESENTSTATS PresentStats;
// Obtain present statistics information for successfully displayed presents
HRESULT hr = g_pd3dSwapChain->GetPresentStats(&PresentStats);
if (SUCCEEDED(hr))
{
// Time-based update
g_LastSyncRefreshCount = PresentStats.SyncRefreshCount;
if ((g_SyncRefreshCount == -1) && (PresentStats.PresentCount != 0))
{
// First time SyncRefreshCount is reported, use it as base
g_SyncRefreshCount = PresentStats.SyncRefreshCount;
}
// Fetch frame from the queue...
UINT TargetRefresh = g_Queue.DequeueFrame(PresentStats.PresentCount);
// If PresentStats returned a really old frame that we no longer have in the queue, just don't do any glitch detection
if (TargetRefresh == FRAME_NOT_FOUND)
return;
if (g_TargetRefreshCount == -1)
{
// This is first time issued frame is confirmed by present stats, so fill target refresh count for all frames in the queue
g_TargetRefreshCount = g_Queue.FillRefreshCounts(PresentStats.PresentCount, g_SyncRefreshCount);
}
else
{
g_TargetRefreshCount++;
g_iFrameNumber++;
// To determine whether we're glitching, see if our estimated refresh count is confirmed
// if the frame is displayed later than the expected vsync count
if (TargetRefresh < PresentStats.PresentRefreshCount)
{
// then, glitch is detected!
// If glitch is too big, don't bother recovering from it, just jump animation
if ((PresentStats.PresentRefreshCount - TargetRefresh) > GLITCH_RECOVERY_LIMIT)
{
g_iStartFrame += PresentStats.SyncRefreshCount - g_SyncRefreshCount;
ResetAnimation();
if (g_bGlitchRecovery)
g_iGlitchesInaRow++;
}
// Otherwise, compute number of immediate presents to recover from it -- if we?re not still trying to recover from another glitch
else if (g_iQueueDelay == 0)
{
// skip frames to catch up to expected refresh count
g_iImmediates = PresentStats.PresentRefreshCount - TargetRefresh;
// QueueDelay specifies # Present calls before another glitch recovery
g_iQueueDelay = g_iImmediates + QUEUE_SIZE;
if (g_bGlitchRecovery)
g_iGlitchesInaRow++;
}
}
else
{
// No glitch, reset glitch count
g_iGlitchesInaRow = 0;
}
}
}
else if (hr == D3DERR_PRESENT_STATISTICS_DISJOINT)
{
// D3DERR_PRESENT_STATISTICS_DISJOINT means measurements should be started from the scratch (could be caused by mode change or DWM on/off transition)
ResetAnimation();
}
// If we got too many glitches in a row, reduce framerate conversion factor (that is, render less frames)
if (g_iGlitchesInaRow == FRAMECONVERSION_GLITCH_LIMIT)
{
if (g_iDoNotFlipNum < FRAMECONVERSION_LIMIT)
{
g_iDoNotFlipNum++;
}
g_iGlitchesInaRow = 0;
g_iShowingDoNotFlipBump = MESSAGE_SHOW;
}
}
샘플 시나리오
다음 그림에서는 백버퍼 수가 4인 애플리케이션을 보여 줍니다. 따라서 실제 Present 큐 길이는 5입니다.
프레임 A는 동기화 간격 수가 1인 화면에 표시되도록 대상으로 하지만 동기화 간격 수가 4인 것으로 감지되었습니다. 따라서 결함이 발생했습니다. 이후의 3개 프레임에는 D3DPRESENT_INTERVAL_FORCEIMMEDIATE 표시됩니다. 글리치는 복구되기 전에 총 8개의 현재 호출을 수행해야 합니다. 다음 프레임은 대상 동기화 간격 수에 따라 표시됩니다.
프레임 동기화에 대한 프로그래밍 권장 사항 요약
제출된 모든 프레젠테이션의 모든 LastPresentCount ID(GetLastPresentCount를 통해 얻은) 및 연결된 예상 PresentRefreshCount의 백업 목록을 만듭니다.
참고 항목
애플리케이션이 D3DPRESENT_DONOTFLIP PresentEx를 호출하면 GetPresentStatistics 호출이 성공하지만 애플리케이션이 창 모드에 있을 때 업데이트된 D3DPRESENTSTATS 구조를 반환하지 않습니다.
GetPresentStatistics를 호출하여 표시된 프레임의 각 현재 ID와 연결된 실제 PresentRefreshCount를 가져와서 애플리케이션이 호출에서 오류 반환을 처리하도록 합니다.
실제 PresentRefreshCount가 예상 PresentRefreshCount보다 늦으면 결함이 검색됩니다. 지연 프레임의 프레젠테이션을 D3DPRESENT_FORCEIMMEDIATE 제출하여 보정합니다.
현재 큐에 하나의 프레임이 늦게 표시되면 대기 중인 모든 후속 프레임이 늦게 표시됩니다. D3DPRESENT_FORCEIMMEDIATE 큐에 대기된 모든 프레임 후에 표시할 다음 프레임만 수정합니다. 따라서 현재 큐 또는 백버퍼 수가 너무 길어서는 안 되므로 따라 잡을 프레임 결함이 적습니다. 최적의 백버퍼 수는 2~4개입니다.
PresentRefreshCount가 실제 PresentRefreshCount보다 늦으면 DWM 제한이 발생했을 수 있습니다. 가능한 솔루션은 다음과 같습니다.
- 현재 큐 길이 줄임
- 현재 큐 길이를 줄이는 것 외에 다른 수단을 사용하여 GPU 메모리 요구 사항 감소(즉, 품질 감소, 효과 제거 등)
- DWM 제한을 방지하기 위해 DwmEnableMMCSS 지정
다음 시나리오에서 애플리케이션 표시 기능 및 프레임 통계 성능을 확인합니다.
- DWM 켜기 및 끄기
- 전체 화면 전용 및 창 모드
- 낮은 기능 하드웨어
애플리케이션이 D3DPRESENT_FORCEIMMEDIATE Present를 사용하여 많은 수의 결함이 있는 프레임에서 복구할 수 없는 경우 다음 작업을 수행할 수 있습니다.
- 더 적은 워크로드로 렌더링하여 CPU 및 GPU 사용량을 줄입니다.
- 비디오 디코딩의 경우 품질을 줄이고 CPU 및 GPU 사용량을 줄여 더 빠르게 디코딩합니다.
Direct3D 9Ex 개선에 대한 결론
Windows 7에서는 프레젠테이션 중에 비디오 또는 계기 프레임 속도를 표시하는 애플리케이션에서 대칭 이동 모델을 선택할 수 있습니다. Flip Model Direct3D 9Ex와 관련된 현재 통계 개선 사항은 결함 감지 및 복구에 대한 실시간 피드백과 함께 프레임당 프레젠테이션 속도를 동기화하는 애플리케이션에 도움이 될 수 있습니다. Direct3D 9Ex 대칭 이동 모델을 채택하는 개발자는 GDI 콘텐츠 및 프레임 속도 동기화에서 별도의 HWND를 대상으로 지정해야 합니다. 이 항목의 세부 정보를 참조하세요. 추가 설명서는 MSDN의 DirectX 개발자 센터를 참조하세요.
작업 호출
프레젠테이션 프레임 속도를 동기화하거나 디스플레이 결함에서 복구하려는 애플리케이션을 만들 때 Windows 7에서 Direct3D 9Ex Flip Model 및 현재 통계를 사용하는 것이 좋습니다.