日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[D3D] - 用PerfHUD来调试商业游戏

發布時間:2024/8/22 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [D3D] - 用PerfHUD来调试商业游戏 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

來源:http://blog.csdn.net/RAINini/archive/2008/10/28/3162112.aspx

?

?? ? ? ? PerfHUD是NV一個非常好用的工具,可以用于查看游戲的運行效率,找出瓶頸,也可以用于分析游戲渲染流程,看每個DPC的渲染操作,包括渲染狀態,所用的shader等,非常強大。

?????????PerfHUD正常的用途是用于調試自己寫的程序,但是有時候看到別的游戲一些好的效果,也想了解是怎么實現的,這時,PerfHUD也可以派上用場。

?? ? ? ? 要使用PerfHUD,就要對自己的D3D程序進行修改,在CreateDevice時,Adapter這個參數不要選用D3DADAPTER_DEFAULT,而是枚舉所有的Adapter,選中Description中帶有“PerfHUD”字符串的那個Adapter,一般來說,對于單顯卡的機器,通常都是第二個Adapter,我沒有多顯卡,所以不知道多顯卡情況下是不是往后順移。

?????????同時,DeviceType不要選D3DDEVTYPE_HAL,而要選D3DDEVTYPE_REF。

?????????通過這樣來創建Device的程序,才能用PerfHUD來掛接并分析,更詳細的創建過程,查看PerfHUD的幫助文檔吧。

?????????由上可以看出,對于別人的程序,Device都不是自己創建的,似乎不能用PerfHUD來分析了,但經過對要分析的程序做一些手腳后,也是可以的,以下拿《魔獸世界》來舉例。

?????????首先,打開VC(我用的2005,2003大同小異,VC6沒試過),確保Options里的這個選項是選中的,

?

?

?

?????????只有選中它了,才能用函數名稱來作為斷點斷住DLL里的函數。

?? ? ? ? 然后用VC來把要分析的游戲的exe執行起來,點擊VC的File->Open ->Project,在彈出的對話框中選中要分析的exe文件,如下圖:

?

?

?

?????????把文件加進來后,在Solution下可以看到該文件,右鍵選Debug->Step into new instance,啟動程序,然后下一個函數斷點,點擊菜單中的Debug->New Breakpoint->Break at function,在彈出的對話框中寫入Direct3DCreate9,如下圖:

?

?

?

?????????點OK后,就下好斷點了,如果一個程序用的D3D,那么應該會在這個斷點斷住,要靠它來獲取IDirect3D9這個interface的指針。

?????????做完以上步驟后,按F5讓程序繼續運行,應該會斷在剛才那個函數斷點,如下圖:

?

?

?

?????????這時按Shift+F11,退出這個函數體,如果創建成功,應該就獲取到了IDirect3D9,因為這個函數的返回值就是IDirect3D9的指針,只需看eax這個寄存器的值,就能找到這個指針,因為eax是存放函數返回值。

?????????在watch窗口里打入eax,當前eax的值是0x0016CFC0。

?????????打開一個memory窗口,把0x0016CFC0這個值敲進去,然后點在memory窗口下點右鍵,用4-byte Integer來查看內存,把0x0016CFC0這塊內存的前4個字節的值拷貝下來,我機器上顯示的值是4b641a98,為什么要拷貝這個值呢,因為一個帶虛擬函數的類的指針所指向的地址,最開頭的4個字節就是虛函數表的指針,通過它能找到各個虛函數的函數地址。

?????????在memory窗口里把這個值加上h后敲進去,同樣用4-byte Integer來查看,得到就是IDirect3D9這個接口的各個函數的入口地址,真正要找的就是CreateDevice這個函數的地址,這時,打開你裝的D3D SDK的d3d.h,搜索IDirect3D9這個接口的聲明,應該會找到如下代碼:

?

DECLARE_INTERFACE_(IDirect3D9, IUnknown)
{
/*** IUnknown methods ***/
STDMETHOD(QueryInterface)(THIS_ REFIID riid,
void** ppvObj) PURE;
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
STDMETHOD_(ULONG,Release)(THIS) PURE;

/*** IDirect3D9 methods ***/
STDMETHOD(RegisterSoftwareDevice)(THIS_
void* pInitializeFunction) PURE;
STDMETHOD_(UINT, GetAdapterCount)(THIS) PURE;
STDMETHOD(GetAdapterIdentifier)(THIS_ UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER9
* pIdentifier) PURE;
STDMETHOD_(UINT, GetAdapterModeCount)(THIS_ UINT Adapter,D3DFORMAT Format) PURE;
STDMETHOD(EnumAdapterModes)(THIS_ UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE
* pMode) PURE;
STDMETHOD(GetAdapterDisplayMode)(THIS_ UINT Adapter,D3DDISPLAYMODE
* pMode) PURE;
STDMETHOD(CheckDeviceType)(THIS_ UINT Adapter,D3DDEVTYPE DevType,D3DFORMAT AdapterFormat,D3DFORMAT BackBufferFormat,BOOL bWindowed) PURE;
STDMETHOD(CheckDeviceFormat)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat) PURE;
STDMETHOD(CheckDeviceMultiSampleType)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType,DWORD
* pQualityLevels) PURE;
STDMETHOD(CheckDepthStencilMatch)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat) PURE;
STDMETHOD(CheckDeviceFormatConversion)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SourceFormat,D3DFORMAT TargetFormat) PURE;
STDMETHOD(GetDeviceCaps)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS9
* pCaps) PURE;
STDMETHOD_(HMONITOR, GetAdapterMonitor)(THIS_ UINT Adapter) PURE;
STDMETHOD(CreateDevice)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS
* pPresentationParameters,IDirect3DDevice9** ppReturnedDeviceInterface) PURE;

#ifdef D3D_DEBUG_INFO
LPCWSTR Version;
#endif
};

?

?????????數了一下,發現CreateDevice是第17個函數,所以應該在虛函數表里的第17個元素,所以在4b641a98h所指向的內存往后數,第17個指針就是CreateDevice的函數入口點,我機器上的值是4b6c1670,應該說,在沒做特別處理的情況下,同個D3D的版本,某個函數的函數地址都是一樣的。

?????????在Disassembly代碼窗口頂部的Address里輸入4b6c1670h這個值,然后敲回車,就能定位到CreateDevice的函數體,按F9下個斷點,然后按F5讓程序繼續運行,應該能斷到這個函數,如下圖:

?

?

??? ? ? ? 這時,查看esp的值,找出調用這個函數的地方,當前esp的值是005a4c4b,在剛進入函數體時,esp保存的是這個函數返回后要繼續執行的下條指令的地址,所以在這條指令的上方,就是調用CreateDevice的代碼了,同樣,在Disassembly窗口里輸入005a4c4bh,定位到該條指令,如下圖:

?

?

?

?????????斷點上方的那條call指令就是調用CreateDevice的地方

?????????上圖中,從那條call指令往上數,第一個push是push this指針,也就是IDirect3D接口的指針push進去,第二個push就push第一個參數,可以看到,它原來是直接push 0的,也就是用D3DADAPTER_DEFAULT來作為第一個參數傳給CreateDevice,再上面的一個push就是放入第二個參數的,可以看到是以下指令完成的,

?

mov ebx,1
push ebx

?

也就是說把1做為第二個參數,其實也就是D3DDEVTYPE_HAL,所以,《魔獸世界》調用CreateDevice是中規中矩的。這時要做的就是把修改這段代碼,從mov ebx,1這條指令開始替換,把它變成push 2,push 1,也就是把傳給CreateDevice的第一個參數改成1,代表第二個Adapter,把第二個參數改成2,也就是D3DDEVTYPE_REF所代表的值。

?????????上圖里的這三條指令就是要替換掉的指令:

?

005A4C3D BB 01 00 00 00 mov ebx,1
005A4C42
53 push ebx
005A4C43 6A
00 push 0

?

?????????要替換成

?

Push 2
Push
1

?

?????????這兩條指令,一共是要替換8個字節的機器碼。

?????????這時可以通過直接修改exe文件本身來達到目的,先把wow.exe復制一份,我把復制后的exe起名為wow_m.exe,然后用UltraEdit打開該exe文件,查找要修改的指令的機器碼,從mov ebx,1這條指令的機器碼搜索起,可以看到,該條指令的機器碼是BB 01 00 00 00,一般來說,搜索的字節越多,越準確,因為你搜得太少,極有可能有好多個地方調用了同條指令,所以我直接把這條指令后面的機器碼也加上,如下圖:

?

?

?

?????????記得把“查找?ASCII”這個勾去掉,然后點下一個,就能定位到該指令所在的地方。一定要確保找到的地方只有一處,如果有多處,就用再多一些的機器碼來搜索。最終定位到的地方如下圖:

?

?

?

?????????從BB這個字節開始替換,把光標定位在第一個B處,然后順序輸入6A 02 6A 01,也就是push 2和push 1的機器碼。這時還剩下4個字節,可全部替換成90,替換后的代碼如下:

?

?

?

?????????修改工作到此結束,保存該exe,然后就可以用PerfHUD來調試了,下圖就是掛接上PerfHUD后的《魔獸世界》運行截圖:

?

?

?

?

總結以上步驟:

1.在程序啟動時下斷點,斷到執行Direct3DCreate9的地方,獲取到IDirect3D指針。

2.用IDirect3D指針獲取到虛函數表指針,查找到CreateDevice的函數體。

3.在該函數體處下斷點,斷住后用esp來找到調用該函數的地方。

4.找到給CreateDevice傳參數的代碼,并修改成PerfHUD所要求的參數。

只要是沒加過密的D3D9程序,應該都可以用以上方法來修改,我只試過《Crysis》,《WOW》,《PES2009》等少數游戲。

希望此文能幫助各位有興趣探索別的游戲制作方法的朋友。

轉載于:https://www.cnblogs.com/hcbin/archive/2010/07/23/1783671.html

總結

以上是生活随笔為你收集整理的[D3D] - 用PerfHUD来调试商业游戏的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。