一个Microsoft? Direct3D?能够处于操做状态或丢失状态。操做状态是设备的正常状态,设备按预期运行并present全部渲染结果。当事件发生时,如全屏应用程序失去键盘输入焦点,设备就转变到丢失状态,这会致使渲染没法进行。丢失状态表现为全部渲染操做的悄然失败,这意味着即便渲染操做失败全部的渲染方法仍能够返回成功码。在这种状况下,IDirect3DDevice9:resent返回错误码D3DERR_DEVICELOST。算法
Direct3D有意没有对可能致使设备丢失的全部状况进行详细说明。一些典型的例子包括窗口失去焦点,例如用户按下了ALT+TAB或弹出了一个系统对话框。设备也会由于电源管理事件而丢失,或者另外一个应用程序进行全屏操做。另外,任何对IDirect3DDevice9::Reset调用的失败会把设备置为丢失状态。缓存
注意 能够保证全部继承自IUnknown的方法在设备丢失后仍能正常工做。设备丢失后,每一个函数通常有三种可能:框架
调用失败,返回值为D3DERR_DEVICELOST – 这意味着应用程序必须发现设备已经丢失,从而知道一些事情没有按照预期进行。
悄然失败,返回值为S_OK或其它值 – 若函数调用悄然失败,则应用程序通常没法区分出“调用成功”或“悄然失败”。
函数返回一个返回值。
对丢失的设备做出响应函数
设备在被重置后,应该从新建立资源(包括显存资源)。若是设备丢失了,那么应用程序应该查询设备状态,看是否能够将之恢复回操做状态。若是不行,那么就等到设备能够被恢复为止。oop
若是设备能够被恢复,那么应用程序应该销毁全部显存资源和交换链,并准备恢复。而后,应用程序调用IDirect3DDevice9::Reset方法。Reset方法是当设备丢失时惟一有效的方法,而且是应用程序可用来把设备从丢失状态恢复到操做状态的惟一方法。除非应用程序释放全部在D3DPOOL_DEFAULT中分配的资源,包括用IDirect3DDevice9::CreateRenderTarget和IDirect3DDevice9::CreateDepthSstencilSurface方法建立的资源,不然Reset将会失败。性能
Direct3D中大部分被频繁调用的方法不返回任何关于设备是否已丢失的信息。应用程序能够继续调用渲染方法,如IDirect3DDevice9:rawPrimitive,而不会收到设备丢失的通知。在Direct3D内部,这些操做被抛弃,直到设备被重置为操做状态为止。ui
经过查询IDirect3DDevice9::TestCooperativeLevel方法的返回值,应用程序能够决定在遇到设备丢失时如何处理。指针
管理资源code
资源管理是将资源从系统内存提高到设备可访问存储器及从设备可访问存储器中抛弃的过程。Microsoft? Direct3D?运行库有本身的基于最近最少使用(least-recently-used)优先级技术的管理算法。当Direct3D检测到在一帧中——在IDirect3DDevice9::BeginScene和IDirect3DDevice9::EndScene调用之间——设备可访问内存没法同时存储全部资源时,它就切换到最近最多使用(most-recently-used)优先级技术。对象
在建立时使用D3DPOOL_MANAGED标志指定一个由系统管理的资源。由系统管理的资源在设备的丢失状态和操做状态间的转换中持续存在。经过调用IDirect3DDevice9::Reset设备能够被重置,而且这类资源能够继续正常运做而无需从新载入图片。可是,若是设备必须被销毁和重建,那么全部用D3DPOOL_MANAGED建立的资源也必须被重建。
在建立时使用D3DPOOL_DEFAULT标志指定把资源放在默认的池中。在默认的池中的资源在设备从丢失状态到操做状态的转换过程当中不持续存在,这些资源必须在调用Reset以前释放,而后重建。
更多有关设备的丢失状态的信息,请参阅丢失的设备。
注意不是全部的类型和用途都支持资源管理。例如,用D3DUSAGE_RENDERTARGET标志建立的对象不支持资源管理。另外,不建议对须要频繁改变其内容的对象使用资源管理。例如,在某些硬件上对一个每帧都需改变的顶点缓存进行自动管理会严重下降性能。可是,对纹理资源来讲这不是一个问题。
例子(摘自codesampler):
......
『当设备丢失以后』
不论经过任何方式发生了设备丢失,全部的操做几乎都会失效,只有Release()能够用——其实D3D会保证有部分操做能够成功,可是也仅仅是“能够”成功而不是“必定”成功,因此你还不如认定丢失的时候全都会失败比较好——以及IDirect3DDevice9::TestCooperativeLevel。所以在设备丢失以后,你应该中止整个游戏循环,而经过反复调用IDirect3DDevice9::TestCooperativeLevel判断设备是否可用。
『IDirect3DDevice9::TestCooperativeLevel』
这个方法检测当前的设备状态。返回值有四种:D3D_OK一切正常,D3DERR_DEVICELOST设备丢失,D3DERR_DEVICENOTRESET设备能够Reset。另外还有D3D9新增的D3DERR_DRIVERINTERNALERROR,遇到这个你就完蛋了,基本不可能恢复了,终止程序吧。
按照顺序来说,若是游戏在正常运行,D3D_OK会返回;若是发生了设备丢失而且在这个时候不能恢复,好比全屏幕模式的时候用户切换到了Windows桌面,就会返回D3DERR_DEVICELOST;若是用户又切换回了游戏,设备能够恢复了(还没恢复呢!只是“能够”恢复而已),就会返回D3DERR_DEVICENOTRESET。
另外,IDirect3DDevice9::Present也会返回相似的值,不过你最好别期望这个,老老实实的用TestCooperativeLevel。由于Present在设备能够恢复的时候仍是返回D3DERR_DEVICELOST(外一句:D3D10的时候TestCooperativeLevel就会彻底整合到Present里面了,可喜可贺可喜可贺)
『处理设备丢失』
看下面的伪代码:
switch (IDirect3DDevice9::TestCooperativeLevel()){
case D3D_OK:
GameLoop();
break;
case D3DERR_DEVICELOST:
break;
case D3DERR_DEVICENOTRESET
OnLostDevice();
IDirect3DDevice9::Reset();
OnResetDevice();
break;
default:
QuitGame();
break;
}
GameLoop()就是你的游戏运行的过程了。把这个switch写在咱们游戏框架的GameMain()部分,具体的位置能够看任何一话附带的源代码。
好像我一直没有讲IDirect3DDevice9::Reset的参数啊?由于只有一个参数,就是指向D3DPRESENT_PARAMS的指针。把你第一次建立设备时使用的D3DPRESENT_PARAMS结构保存起来,供Reset来用。
OnLostDevice()就是Release掉全部D3DPOOL_DEFAULT的资源,OnResetDevice()就是Create*()恢复啦!你可能注意到ID3DXFont、ID3DXSprite等等都有同名的方法,就是在这个时候调用的。若是你没有这么作,也就是说还保留着任何D3DPOOL_DEFAULT的资源的话,IDirect3DDevice9::Reset就必定会失败。
另外在OnResetDevice里面你还要从新进行SetRenderState、SetSamplerState等等,Reset以后这些东西也丢失了。实际上Reset和从新建立一次设备相似,所不一样的是从新建立设备的话你须要连D3DPOOL_MANAGED的资源也Release掉。这个话题就不讨论了。
从代码能够看出来,D3DERR_DEVICELOST时程序什么都没作,只是在傻等。我认为这是一个好习惯,由于实在不能保证在D3DERR_DEVICELOST时除了Release还能干什么,与其这样还不如等设备能用了再说。
实在懒得管资源的话,所有D3DPOOL_MANAGED好了。至于渲染对象?本身想办法。
『人工制造“设备丢失”』
“干吗还要制造设备丢失啊?”若是更改游戏分辨率、色深、切换全屏幕及窗口状态,进行这样的操做也要经过Reset,一样的,Reset以前也要释放掉全部D3DPOOL_DEFAULT资源(其实严格来讲,还有更多的资源也要释放,不过在2D下基本不会建立这类资源,你就不用管了)而且调用ID3DXSprite::OnLostDevice之类的方法。这就是人工制造“设备丢失”了。实际上在这个过程设备并无真正的丢失,只是会有一段时间处于不可用的状态,此时Reset还没有返回,整个D3D设备就好像死了同样。举个例子,你切换桌面分辨率,会有那么一段时间显示器上什么都不显示,而后很快就正常了。和这个现象是同一个缘由。Reset成功后记得恢复资源。 你可能注意到这里的Reset和上面的Reset不是一回事。的确是这样,这里是为了重设状态而不是恢复设备。所以更改分辨率、色深的Reset须要写到switch外面,也就是别和它搅和的意思-_-bb。并且你只须要OnLostDevice -> Reset -> OnResetDevice。记住:正确的调用Reset不会形成设备丢失,这个概念别弄混了。