我在程序中实现抓屏,根据 Various methods for capturing the screen 文章中的两种方式(以下时间的计算都为release版)。发现使用GDI方式抓一次屏的时间大概20毫秒左右,但是使用DirectX9抓一次屏的时间竟然是400毫秒左右。各位看看问题出现在哪里?DirectX不会就是这样的速度吧?
DirectX code:    InitD3D(m_hWnd);
    DWORD u32Time = ::GetTickCount();
    g_pd3dDevice->CreateOffscreenPlainSurface(ScreenWidth, ScreenHeight,
    D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pSurface, NULL);
    g_pd3dDevice->GetFrontBufferData(0, pSurface);
    D3DXSaveSurfaceToFile("Desktop.bmp",D3DXIFF_BMP,pSurface,NULL,NULL);//save the bmp
    pSurface->Release(); 
    u32Time = ::GetTickCount() - u32Time;
我是想找个更快的抓屏方法,16ms都感觉有点慢,因为我的电脑配置比较好。可是换成DirectX竟然400毫秒。
各位要是有更好更快的抓屏方法请贡献一个,不胜感觉。Thanks in advance!

解决方案 »

  1.   

    你可以分步调试一下,看看那一步时间最长。FillRect 居然也很慢?
      

  2.   

    to:asa5880  我的显卡是集成的 。我不知道我的初始化对不对(现把初始化code附上),第一次使用DirectX。
    to:zhoujianhei    g_pd3dDevice-> GetFrontBufferData(0,   pSurface); 这个函数执行最长  300多ms
                       D3DXSaveSurfaceToFile("Desktop.bmp",D3DXIFF_BMP,pSurface,NULL,NULL); 次之 几十ms. 
                   我希望是抓屏后保存在内存,然后执行压缩之类的再送出。
                     各位继续!!!HRESULT InitD3D(HWND hWnd)
    {
    D3DDISPLAYMODE ddm;
    D3DPRESENT_PARAMETERS d3dpp; if((g_pD3D=Direct3DCreate9(D3D_SDK_VERSION))==NULL)
    {
    AfxMessageBox("Unable to Create Direct3D ");
    return E_FAIL;
    } if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&ddm)))
    {
    AfxMessageBox("Unable to Get Adapter Display Mode");
    return E_FAIL;
    } ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS)); d3dpp.Windowed=WINDOW_MODE;
    d3dpp.Flags=D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
    d3dpp.BackBufferFormat=ddm.Format;
    d3dpp.BackBufferHeight=nDisplayHeight=gScreenRect.bottom =ddm.Height;
    d3dpp.BackBufferWidth=nDisplayWidth=gScreenRect.right =ddm.Width;
    d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
    d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
    d3dpp.hDeviceWindow=hWnd;
    d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT;
    d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT; if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING ,&d3dpp,&g_pd3dDevice)))
    {
    AfxMessageBox("Unable to Create Device");
    return E_FAIL;
    } if(FAILED(g_pd3dDevice->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pSurface, NULL)))
    {
    AfxMessageBox("Unable to Create Surface");
    return E_FAIL;
    } return 0;
    },第一次使用DirectX.
    Init code:
    HRESULT InitD3D(HWND hWnd)
    {
    D3DDISPLAYMODE ddm;
    D3DPRESENT_PARAMETERS d3dpp;
    if((g_pD3D=Direct3DCreate9(D3D_SDK_VERSION))==NULL)
    {
    return E_FAIL;
    }
    if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&ddm)))
    {
    return E_FAIL;
    }
    ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
    d3dpp.Windowed=WINDOW_MODE;
    d3dpp.Flags=D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
    d3dpp.BackBufferFormat=ddm.Format;
    d3dpp.BackBufferHeight=nDisplayHeight=gScreenRect.bottom =ddm.Height;
    d3dpp.BackBufferWidth=nDisplayWidth=gScreenRect.right =ddm.Width;
    d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
    d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
    d3dpp.hDeviceWindow=hWnd;
    d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT;
    d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;
    if(FAILED(g_pD3D->CreateDevic(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING ,&d3dpp,&g_pd3dDevice)))
    {
    return E_FAIL;
    } if(FAILED(g_pd3dDevice->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pSurface, NULL)))
    {
    return E_FAIL;
    } return 0;
    }
      

  3.   

    Sorry!版面没有控制好,后面的HRESULT InitD3D(HWND   hWnd) 重发了。
      

  4.   

    http://vegeta.blog.enorth.com.cn/article/50706.shtml这个速度呢?以前写的。跟QQ差不多.
      

  5.   

    to:Prince_vegeta  十分感谢您的关注,可是我的是公司的网,只给我开通了csdn codeproject 等网站。这个我只能回去再看。
    期待高手出来解惑..............................
      

  6.   

    你可能是听说,DX可以直接操作硬件,效率会更高吧!但是你没有理解DX是用来做什么的,优势在哪里,没有显卡在绘图渲染等方面会差很多,抓屏只是简单读取内存屏幕DC,你用DX根本没有优势,而且DX好多COM对象都要初始化,最好用GDI来做,实在性能要求太高,就不用API,自己来实现它
    个人愚见,有不对的还请大牛指正
      

  7.   

    普通应用直接读DC就行,回家上VCKBASE上看看,我记得有两篇仿QQ截图的文章。
      

  8.   

    to asat5880: 是的,之前我就是用gdi做的时间还少点,但是还不能满足需求,后来上网看到有些网友提出的。我才去接触DirectX,我是对这个一点不懂的。
    ”就不用API,自己来实现它 “ 对于这个不用api自己来实现,由于能力不够,是否可以给个自己实现的思路?只要思路就可以了,我会去实现。Thanksto all:有好建议的请提出来,热烈欢迎!  能详细的就给详细点,不然就给个思路。
    Thanks in advance!!!
      

  9.   

    to Prince_vegeta: vckbase 上面的关于qq相关文章看过了,不适应我的要求。 类似于远程监控,对速度和效率要求比较高一点。thank you all the some!
      

  10.   

    能不能帖出你抓屏的GDI代码,我看怎么还保存文件的,如果是远程控制项目的话,根本不需要保存文件,就象你说的保存在
    内存压缩再SEND,当然然取的并不一定是全屏,是有时机与有效区域,你看下mircosoft的远程桌面刷新方式就知道了,
    尽量减少I/O操作
      

  11.   

    to asa5880:
    保存文件只是为了查看一下抓的屏对不对,其实真的要实现的时候是只要buffer就可以了的。
    “mircosoft的远程桌面刷新方式”从哪里可以看到mircosoft的远程桌面刷新方式??  请再说明一下,谢谢!
      

  12.   

    GetFrontBufferData
    ---------------
    主表面的buffer数据在内部是加了锁保护的,读取时要等到解锁才能返回。与刷新率相关。
      

  13.   

    dx直接处理自己生成的图像抓取会很好
    但是如同前面说的,抓取别的程序生成的窗口的数据并不占据优势; 至于慢的原因抓取的速度20ms应该是够快的了,人眼可以识别的25帧, 平均40ms就够了另外, 你用的时间技术器不适合做这个判断, 它太粗了, 要找更高精度的计数器来计算
      

  14.   

    对头,你的时间计数器不行,去google搜一下 高精度时钟windows之类的
    再说你把保存磁盘文件的时间也计算进去了,磁盘io的速度是很慢的。
      

  15.   

    to:captain_X   我的的GDI 20ms时间是除去了保存文件之后的时间。
    to:shrnruo     是否我在GetFrontBufferData 之前进行刷新屏幕的话程序执行会更快一点。感谢大家关注,请继续!!!
      

  16.   

    看看我的程序吧。www.software168.com
      

  17.   

    我搞图片压缩的时候使用过SSE2指令,发现指令居然比我直接写代码还要慢
    后来才发现在debug状态的时候,根本发挥不出硬件指令的优势,在release下面快了n倍,
    楼主可以试试用release版对比
      

  18.   

    感谢 iorikingdom 。我的时间都是在release下测出来的。
      

  19.   

    D3D SDK文档中关于 GetFrontBufferData说明中说了, FrontBuffer非常慢,不能使用在高效程序中,另外还有一句,它是获取消除锯齿图像的唯一方法。