zoukankan      html  css  js  c++  java
  • 获取Ogre或D3D的渲染结果的效率问题

    在Ogre中获取渲染结果可以使用RenderTarget的copyContentsToMemory方法, 例:

    char* src = new char[mWindow->getWidth() * mWindow->getHeight() * 4];
    Ogre::PixelBox* pixbox = new Ogre::PixelBox(mWindow->getWidth(), mWindow->getHeight(), 1, Ogre::PF_X8R8G8B8, src );
    mWindow->copyContentsToMemory(*pixbox, Ogre::RenderTarget::FB_AUTO);

    mWindow为当前渲染窗口RenderWindow,如果使用RTT(渲染到纹理)也是同样的处理

    需要注意的是导出格式应该是PF_X8R8G8B8,避免格式转换带来性能损耗

    不幸的是,实际中发现这个方法出奇的慢

    一个上百帧的场景竟然因为这一句话下降到了二三十帧

    一般来说从GPU显存将数据复制到CPU内存是个很慢的过程,但这么慢也实在是太夸张了

    查看copyContentsToMemory的实现,大概是下面的样子(做了简化):

     void D3D9Device::copyContentsToMemory(const PixelBox &dst)
        {
           IDirect3DSurface9 *surface = NULL;
               D3DLOCKED_RECT lrect; 
     
               mDevice->CreateOffscreenPlainSurface(width, height, format, D3DPOOL_SYSTEMMEM, surface, 0);
     
               IDirect3DSurface9 *backSurface;
               mDevice->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&backSurface);
               mDevice->GetRenderTargetData(backSurface, surface);
     
               surface->LockRect(&lrect, NULL,  D3DLOCK_READONLY);
               memcpy(dst.data, lrect.pBits, dst.getWidth() * dst.getHeight()*4);
               surface->UnlockRect();
    surface
    ->Release(); tmp->Release(); }

    大意是在内存(D3DPOOL_SYSTEMMEM)中创建离屏表面

    然后将后缓冲中数据复制到该表面中(GetRenderTargetData)

    最后锁定该表面获取内存指针完成数据复制

    其中完成将数据从GPU显存复制到CPU内存的步骤为GetRenderTargetData

    这么实现可以说没有任何问题,简直就是标准做法

    测试了一下发现GetRenderTargetData方法用时为0毫秒,也就是说足够的快

    实际瓶颈出在LockRect方法上,测试场景中每次调用用时达到30多毫秒

    原则上来说,该表面在内存中创建,并没有在场景中使用,锁定不应该有任何消耗

    直接使用D3D测试时,也发现该方法用时为0,实在想不通是什么原因

    ...

    一番周折,最后想到一个非常规的解决办法:

    仅在第一次创建离屏表面时锁定、解锁以获取数据区指针,之后直接利用该指针完成数据复制

    这么做之所以成立是因为创建的离屏表面实际上也并不需要锁定

    每次只要调用GetRenderTargetData将数据从GPU显存复制出来即可

    使用Ogre的话,实现这个稍微有点麻烦,因为Ogre并不支持直接访问Direct3D

    需要修改Ogre和RenderSystem_Direct3D9插件的代码

    不过这是目前个人想到的解决这个问题的最好办法了

    注:Ogre中可以直接使用D3D,不需要修改Ogre源码,参考下一篇:在Ogre中直接使用D3D

  • 相关阅读:
    leetcode 2 Add Two Numbers
    leetcode1
    二叉树的最大高度和最大宽度
    插入排序
    eventEmitter学习
    用node.js做一个爬虫
    HTLM5 WebSocket权威指南
    (new Function("return " + json))();
    JS中的this变量的使用介绍
    node.js 模块加载原理
  • 原文地址:https://www.cnblogs.com/wiki3d/p/4770665.html
Copyright © 2011-2022 走看看