作者:hhstudy
博客: http://hi.baidu.com/hhstudy
转载请在文章开头注明出处
垂直同步是vertical synchronization的简称。基本思路是将显示器的刷新周期和显卡输出画面的周期同步起来,其目的是为了避免一种称之为“画面撕裂”的现象。顾名思义,“画面撕裂”其实就是画面移动较快的时候,画面看上去是两截,上面半副图和下面半副图就像是两张相差不多的图的各自半部分拼凑起来的一样。这现象恐怕打游戏的都见过。垂直同步的原理和“画面撕裂”的原因请自行谷歌。
下面主要研究某卡驱动是如何猥琐的实现强制覆盖应用程序的垂直同步设置。以及自己实现一个覆盖应用程序垂直同步设置的程序。
环境配置
OS win8.1_x86 显卡 Nvidia GTX 660
在UserMode中,垂直同步至少可以在2个地方设置(其实一般也就这两个地方了)。
1.由程序发起调用 ,程序在CreateDevice 的时候指定pPresentationParameters->PresentationInterval = D3DPRESENT_INTERVAL_ONE(TWO,THREE,FOUR也可以) 参数即可。
HRESULT CreateDevice(
[in] UINT Adapter,
[in] D3DDEVTYPE DeviceType,
[in] HWND hFocusWindow,
[in] DWORD BehaviorFlags,
[in, out] D3DPRESENT_PARAMETERS *pPresentationParameters,
[out, retval] IDirect3DDevice9 **ppReturnedDeviceInterface
);
PFND3DDDI_PRESENTCB pfnPresentCb
__checkReturn HRESULT APIENTRY CALLBACK pfnPresentCb(
_In_ HANDLE hDevice,
_In_ const D3DDDICB_PRESENT *pData
);
ChildEBP RetAddr Args to Child
bffe7b90 8c6422d9 8110d858 bffe7cd0 bffe7c8c dxgkrnl!DXGCONTEXT::Present (FPO: [Non-Fpo])
bffe7d38 92350ea0 00000000 c1dc1db8 bffe7d54 dxgkrnl!DxgkPresent+0x24d (FPO: [Non-Fpo])
bffe7d48 81d1b377 00fbb170 0394f3f8 778b2da4 win32k!NtGdiDdDDIPresent+0x14 (FPO: [1,0,0])
bffe7d48 778b2da4 00fbb170 0394f3f8 778b2da4 nt!KiSystemServicePostCall (FPO: [0,3] TrapFrame @ bffe7d54)
0394f130 76896bdc 70747363 00fbb170 00fbb170 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
0394f134 70747363 00fbb170 00fbb170 0587d000 GDI32!NtGdiDdDDIPresent+0xa (FPO: [1,0,0])
0394f3f8 53134e24 00fbb0b0 0394f540 00fbb170 d3d9!PresentCB+0xe2 (FPO: [2,171,4])
WARNING: Stack unwind information not available. Following frames may be wrong.
0394f424 53134b58 0394f540 00000000 0587d000 nvd3dum!QueryOglResource+0x21b84
0394f46c 53134d1b 0394f540 0587d000 025b5140 nvd3dum!QueryOglResource+0x218b8
0394f484 531079ab 0394f540 00000504 0587d000 nvd3dum!QueryOglResource+0x21a7b
0394f760 531094db 00000504 036c9040 03789818 nvd3dum+0x6979ab
0394f778 70870b2a 0587d000 03789818 00000001 nvd3dum+0x6994db
0394f7a0 70871665 03789314 00000001 00000000 d3d9!CBatchFilterI::ProcessBatch+0x4c2 (FPO: [2,3,4])
0394f7b8 70870472 0394f7cc 76ae17ad 036c9040 d3d9!CBatchFilterI::WorkerThread+0x2d (FPO: [0,0,4])
0394f7c0 76ae17ad 036c9040 0394f810 77893af4 d3d9!CBatchFilterI::LHBatchWorkerThread+0xd (FPO: [1,0,0])
0394f7cc 77893af4 036c9040 2cb22ace 00000000 KERNEL32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
0394f810 77893acd ffffffff 778c42a6 00000000 ntdll!__RtlUserThreadStart+0x20 (FPO: [Non-Fpo])
0394f820 00000000 70870465 036c9040 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [2,2,0])
NTSTATUS APIENTRY D3DKMTPresent(
_In_ const D3DKMT_PRESENT *pData
);
typedef struct _D3DKMT_PRESENT {
union {
D3DKMT_HANDLE hDevice;
D3DKMT_HANDLE hContext;
};
HWND hWindow;
D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;
D3DKMT_HANDLE hSource;
D3DKMT_HANDLE hDestination;
UINT Color;
RECT DstRect;
RECT SrcRect;
UINT SubRectCnt;
const RECT *pSrcSubRects;
UINT PresentCount;
D3DDDI_FLIPINTERVAL_TYPE FlipInterval;
D3DKMT_PRESENTFLAGS Flags;
ULONG BroadcastContextCount;
D3DKMT_HANDLE BroadcastContext[D3DDDI_MAX_BROADCAST_CONTEXT];
HANDLE PresentLimitSemaphore;
D3DKMT_PRESENTHISTORYTOKEN PresentHistoryToken;
#if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WIN8)
D3DKMT_PRESENT_RGNS *pPresentRegions;
#endif
} D3DKMT_PRESENT;
1: kd> dd 00fbb170
00fbb170 800014c0 00500442 00000000 40002840
00fbb180 00000000 00000000 00000000 00000000
00fbb190 00000000 00000000 00000000 00000000
00fbb1a0 00000000 00000000 00000001 00000000
00fbb1b0 00097f37 00000000 00001004 00000000
00fbb1c0 00000000 00000000 00000000 00000000
00fbb1d0 00000000 00000000 00000000 00000000
00fbb1e0 00000000 00000000 00000000 00000000
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课