directx中丢失的设备(lost device)
丢失的设备

一个Microsoft? Direct3D?可以处于操作状态或丢失状态。操作状态是设备的正常状态,设备按预期运行并present所有渲染结果。当事件发生时,如全屏应用程序失去键盘输入焦点,设备就转变到丢失状态,这会导致渲染无法进行。丢失状态表现为所有渲染操作的悄然失败,这意味着即使渲染操作失败所有的渲染方法仍可以返回成功码。在这种情况下,IDirect3DDevice9:resent返回错误码D3DERR_DEVICELOST。

Direct3D有意没有对可能导致设备丢失的所有情况进行详细说明。一些典型的例子包括窗口失去焦点,例如用户按下了ALT+TAB或弹出了一个系统对话框。设备也会因为电源管理事件而丢失,或者另一个应用程序进行全屏操作。另外,任何对IDirect3DDevice9::Reset调用的失败会把设备置为丢失状态。

注意   可以保证所有继承自IUnknown的方法在设备丢失后仍能正常工作。设备丢失后,每个函数一般有三种可能:

调用失败,返回值为D3DERR_DEVICELOST – 这意味着应用程序必须发现设备已经丢失,从而知道一些事情没有按照预期进行。 
悄然失败,返回值为S_OK或其它值 – 若函数调用悄然失败,则应用程序一般无法区分出“调用成功”或“悄然失败”。 
函数返回一个返回值。 
对丢失的设备作出响应

设备在被重置后,应该重新创建资源(包括显存资源)。如果设备丢失了,那么应用程序应该查询设备状态,看是否可以将之恢复回操作状态。如果不行,那么就等到设备可以被恢复为止。

如果设备可以被恢复,那么应用程序应该销毁所有显存资源和交换链,并准备恢复。然后,应用程序调用IDirect3DDevice9::Reset方法。Reset方法是当设备丢失时唯一有效的方法,并且是应用程序可用来把设备从丢失状态恢复到操作状态的唯一方法。除非应用程序释放所有在D3DPOOL_DEFAULT中分配的资源,包括用IDirect3DDevice9::CreateRenderTarget和IDirect3DDevice9::CreateDepthSstencilSurface方法创建的资源,否则Reset将会失败。

Direct3D中大部分被频繁调用的方法不返回任何关于设备是否已丢失的信息。应用程序可以继续调用渲染方法,如IDirect3DDevice9:rawPrimitive,而不会收到设备丢失的通知。在Direct3D内部,这些操作被抛弃,直到设备被重置为操作状态为止。

通过查询IDirect3DDevice9::TestCooperativeLevel方法的返回值,应用程序可以决定在遇到设备丢失时如何处理。

管理资源

资源管理是将资源从系统内存提升到设备可访问存储器及从设备可访问存储器中抛弃的过程。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):

以下内容为程序代码:

//-----------------------------------------------------------------------------
// Name: invalidateDeviceObjects()
// Desc: If the lost device can be restored, the application prepares the 
//       device by destroying all video-memory resources and any 
//       swap chains. This is typically accomplished by using the SAFE_RELEASE 
//       macro.
//-----------------------------------------------------------------------------
HRESULT invalidateDeviceObjects( void )
{
    //
    // To see how mismanagement of an object''s reference counter can cause us
    // problems when calling Reset on the device, uncomment the line below.
    // The line below will call AddRef() on the vertex buffer object, which w
    // ill add one to the vertex buffer''s reference count. This will cause it
    // to hang around after we call Release() on it, which is not what we 
    // wanted to happen here.
    //
    //g_pVertexBuffer->AddRef();

//
    // NOTE: You could use the SAFE_RELEASE macro to invalidate your device 
    //       objects like so:
    //
     SAFE_RELEASE( g_pTexture )
     SAFE_RELEASE( g_pVertexBuffer )
     SAFE_RELEASE( g_pTeapotMesh )
    
    return S_OK;
}

//-----------------------------------------------------------------------------
// Name: restoreDeviceObjects()
// Desc: You are encouraged to develop applications with a single code path to 
//       respond to device loss. This code path is likely to be similar, if not 
//       identical, to the code path taken to initialize the device at startup.
//-----------------------------------------------------------------------------
HRESULT restoreDeviceObjects( void )
{
    //
    // Set some important state settings...
    //

D3DXMATRIX matProj;
    D3DXMatrixPerspectiveFovLH( &matProj, D3DXToRadian( 45.0f ),
                                640.0f / 480.0f,
                                //(float)(g_d3dpp.BackBufferWidth / g_d3dpp.BackBufferHeight), 
                                0.1f, 100.0f );
    g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );

g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
    g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
    g_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, TRUE );

g_pd3dDevice->SetLight( 0, &g_pLight0 );
    g_pd3dDevice->LightEnable( 0, TRUE );

g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, D3DCOLOR_COLORVALUE( 0.2f, 0.2f, 0.2f, 1.0f ) );

//
    // Create a texture object...
    //

D3DXCreateTextureFromFile( g_pd3dDevice, "test.bmp", &g_pTexture );

g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
    g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );

//
    // Create a vertex buffer...
    //
    // NOTE: When a device is lost, vertex buffers created using  
    // D3DPOOL_DEFAULT must be released properly before calling 
    // IDirect3DDevice9::Reset.
    //

g_pd3dDevice->CreateVertexBuffer( 4*sizeof(QuadVertex),
                                      D3DUSAGE_WRITEONLY,
                                      QuadVertex::FVF_Flags,
                                      //D3DPOOL_MANAGED, // Does not have to be properly Released before calling IDirect3DDevice9::Reset
                                      D3DPOOL_DEFAULT,   // Must be Released properly before calling IDirect3DDevice9::Reset
                                      &g_pVertexBuffer, NULL );
    void *pVertices = NULL;

g_pVertexBuffer->Lock( 0, sizeof(g_quadVertices), (void**)&pVertices, 0 );
    memcpy( pVertices, g_quadVertices, sizeof(g_quadVertices) );
    g_pVertexBuffer->Unlock();

//
    // Create a mesh object...
    //
    // NOTE: When a device is lost, meshes created using D3DXMESH_DYNAMIC 
    // must be released properly before calling IDirect3DDevice9::Reset.
    //

D3DXLoadMeshFromX( "teapot.x",
                       //D3DXMESH_SYSTEMMEM, // Does not have to be properly Released before calling IDirect3DDevice9::Reset
                       //D3DXMESH_MANAGED,   // Does not have to be properly Released before calling IDirect3DDevice9::Reset
                       //D3DXMESH_WRITEONLY, // Does not have to be properly Released before calling IDirect3DDevice9::Reset
                       D3DXMESH_DYNAMIC,     // Must be Released properly before calling IDirect3DDevice9::Reset
                       g_pd3dDevice,
                       NULL, NULL, NULL, NULL, &g_pTeapotMesh );
    return S_OK;
}

//-----------------------------------------------------------------------------
// Name: render()
// Desc: 
//-----------------------------------------------------------------------------
void render( void )
{
    //
    // Before we render, we need to make sure we haven''t lost our device.
    // If we have, we''ll need to restore it before we can continue.
    //

HRESULT hr;

if( g_bDeviceLost == true )
    {
        // Yield some CPU time to other processes
        Sleep( 100 ); // 100 milliseconds

//
        // Test the cooperative level to see if it''s okay to render.
        // The application can determine what to do on encountering a lost 
        // device by querying the return value of the TestCooperativeLevel 
        // method.
        //

if( FAILED( hr = g_pd3dDevice->TestCooperativeLevel() ) )
        {
            // The device has been lost but cannot be reset at this time. 
            // Therefore, rendering is not possible and we''ll have to return 
            // and try again at a later time.
            if( hr == D3DERR_DEVICELOST )
                return;

// The device has been lost but it can be reset at this time. 
            if( hr == D3DERR_DEVICENOTRESET )
            {
                //
                // If the device can be restored, the application prepares the 
                // device by destroying all video-memory resources and any 
                // swap chains. 
                //

invalidateDeviceObjects();

//
                // Then, the application calls the Reset method.
                //
                // Reset is the only method that has an effect when a device 
                // is lost, and is the only method by which an application can 
                // change the device from a lost to an operational state. 
                // Reset will fail unless the application releases all 
                // resources that are allocated in D3DPOOL_DEFAULT, including 
                // those created by the IDirect3DDevice9::CreateRenderTarget 
                // and IDirect3DDevice9::CreateDepthStencilSurface methods.
                //

hr = g_pd3dDevice->Reset( &g_d3dpp );

if( FAILED(hr ) )
                    return;

//
                // Finally, a lost device must re-create resources (including  
                // video memory resources) after it has been reset.
                //

restoreDeviceObjects();
            }

return;
        }

g_bDeviceLost = false;
    }

//
    // Render a teapot and textured quad...
    //

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
                         D3DCOLOR_COLORVALUE(0.35f,0.53f,0.7f,1.0f), 1.0f, 0 );

g_pd3dDevice->BeginScene();
    {
        D3DXMATRIX matView;
        D3DXMATRIX matWorld;
        D3DXMATRIX matRotation;
        D3DXMATRIX matTranslation;

D3DXMatrixIdentity( &matView );
        g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

// Place and render first teapot...
        D3DXMatrixRotationYawPitchRoll( &matRotation, D3DXToRadian(g_fSpinX), D3DXToRadian(g_fSpinY), 0.0f );
        D3DXMatrixTranslation( &matTranslation, 1.5f, 0.0f, 6.0f );
        matWorld = matRotation * matTranslation;
        g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

g_pd3dDevice->SetMaterial( &g_teapotMtrl );
        g_pTeapotMesh->DrawSubset(0);

// Place and render textured quad...
        D3DXMatrixTranslation( &matTranslation, -1.5f, 0.0f, 6.0f );
        matWorld = matRotation * matTranslation;
        g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

g_pd3dDevice->SetMaterial( &g_quadMtrl );
        g_pd3dDevice->SetTexture( 0, g_pTexture );
        g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer, 0, sizeof(QuadVertex) );
        g_pd3dDevice->SetFVF( QuadVertex::FVF_Flags );
        g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
    }
    g_pd3dDevice->EndScene();

//
    // If Present fails with D3DERR_DEVICELOST the application needs to be 
    // notified so it cleanup resources and reset the device.
    //

hr = g_pd3dDevice->Present( NULL, NULL, NULL, NULL );

if( g_bHandleLostDevice == true )
{
if( hr == D3DERR_DEVICELOST )
g_bDeviceLost = true;
}
}

『当设备丢失之后』

  不论通过任何方式发生了设备丢失,所有的操作几乎都会失效,只有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不会造成设备丢失,这个概念别弄混了。

(转)directx中丢失的设备(lost device)的更多相关文章

  1. Managed DirectX中的DirectShow应用(简单Demo及源码)

    阅读目录 介绍 准备工作 环境搭建 简单Demo 显示效果 其他 Demo下载 介绍 DirectX是Microsoft开发的基于Windows平台的一组API,它是为高速的实时动画渲染.交互式音乐和 ...

  2. Centos7中网络及设备相关配置

    centos7中,不再赞成使用ifconfig工具,取而代之的是nmcli工具,服务管理也是以systemctl工具取代了service,这些之前版本的工具虽然在centos7中还可以继续使用,只是出 ...

  3. 设备模型(device-model)之平台总线(bus),驱动(driver),设备(device)

    关于关于驱动设备模型相关概念请参考<Linux Device Drivers>等相关书籍,和内核源码目录...\Documentation\driver-model 简单来说总线(bus) ...

  4. Windows下USB磁盘开发系列二:枚举系统中所有USB设备

    上篇 <Windows下USB磁盘开发系列一:枚举系统中U盘的盘符>介绍了很简单的获取系统U盘盘符的办法,现在介绍下如何枚举系统中所有USB设备(不光是U盘). 主要调用的API如下: 1 ...

  5. ARM Linux 3.x的设备树(Device Tree)

    1. ARM Device Tree起源 Linus Torvalds在2011年3月17日的ARM Linux邮件列表宣称“this whole ARM thing is a f*cking pai ...

  6. win7 64位 python启动报错:无法启动此程序,因为计算机中丢失api-ms-win-crt-process-l1-1-0.dll

    安装python3.7,安装成功后,在cmd窗口输入python检查是否安装成功,报错:无法启动此程序,因为计算机中丢失api-ms-win-crt-process-l1-1-0.dll 在网上查询了 ...

  7. 从串口驱动的移植看linux2.6内核中的驱动模型 platform device & platform driver【转】

    转自:http://blog.csdn.net/bonnshore/article/details/7979705 写在前面的话: 博主新开了个人站点:你也可以在这里看到这篇文章,点击打开链接 本文是 ...

  8. 无法启动此程序,因为计算机中丢失 MSVCP120.dll。尝试安装该程序以解决此问题

    重装了下系统(Windows 7),发现先前装的一些软件大部分不能正确启动,更为奇怪的是,即使我重装了该软件,打开的软件界面的时候,报如下错误:“无法启动此程序,因为计算机中丢失 MSVCP120.d ...

  9. 无法启动此程序 ,因为计算机中丢失MSVCP120.dll

    1.文件丢失问题 无法启动此程序 ,因为计算机中丢失MSVCP120.dll 具体如下图所示: 等dll文件丢失,可以去下载 DirectX修复工具去修复即可 http://www.pc6.com/s ...

随机推荐

  1. 算法笔记_016:凸包问题(Java)

    目录 1 问题描述 2 解决方案 2.1 蛮力法 1 问题描述 给定一个平面上n个点的集合,它的凸包就是包含所有这些点的最小凸多边形,求取满足此条件的所有点. 另外,形象生动的描述: (1)我们可以把 ...

  2. Android静默安装和静默卸载代码

    静默顾名思义就是静静的默默地,静默安装和静默卸载的意思也就是说在后台默默地安装和卸载. 最近的一个app应用分发的项目中app下载的模块,下载完成之后,用户可以通过这个app进行安装,为了提高用户的体 ...

  3. js 函数节流throttle 函数去抖debounce

    1.函数节流throttle 通俗解释: 假设你正在乘电梯上楼,当电梯门关闭之前发现有人也要乘电梯,礼貌起见,你会按下开门开关,然后等他进电梯: 但是,你是个没耐心的人,你最多只会等待电梯停留一分钟: ...

  4. Autofac3 在MVC4中的运用原理

    这是一种新的开发模式,注入开发模式,或者叫它IOC模式,说起IOC你可以这样去理解它,它为你的某个实现流出一个注入点,你生产的对象,可以根据你之前的配置进行组合.  IOC全称是Inversion o ...

  5. [Done]com.aerospike.client.AerospikeException: Error Code 12: Bin type error

    今天遇到了一个问题:com.aerospike.client.AerospikeException: Error Code 12: Bin type error 异常栈: 网上找了一些资料:https ...

  6. oracle中如何设置主键并且让其自动增长

    由于oracle中是没有自动增长的的,需要自己去进行写触发器等方式去进行设置: 找了一下他人写的,有两种方法可以设置主键,一种是自增长主键,另一种就是生成唯一序列. 一.自增长主键 我创建一个用户的信 ...

  7. 关于RDS备份文件使用wget下载提示403 Forbidden的情况

    关于RDS备份文件使用wget下载提示403 Forbidden的情况 使用wget下载提示403错误当我们RDS物理备份文件时,例如: 原因: URL中包含有特殊字符比如&,从而造成URL被 ...

  8. Codis作者黄东旭细说分布式Redis架构设计和踩过的那些坑们

    转载自:http://www.open-open.com/lib/view/open1436360508098.html

  9. 创建你的第一个Android PHP应用

    google的开源移动操作系统Android给智能手机市场带来了风暴.不像Apple,对想要为水果市场(Iphone App Store)提供应用软件的开发者们有着严格的指导原则以及要求,Google ...

  10. 微软的SQLHelper类(含完整中文注释)

    using System; using System.Data; using System.Xml; using System.Data.SqlClient; using System.Collect ...