获取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插件的代码

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

时间: 2024-10-09 06:15:42

获取Ogre或D3D的渲染结果的效率问题的相关文章

jsonp跨域访问servlet接口获取json数组,并且渲染数据,前后端完整

啊哈哈哈哈哈哈哈哈哈哈哈我太激动了~ 其实这个工作我一直在拖延啊,就觉得哇,好难啊,不想做欸= = 然后硬着头皮研究了一整个下午+晚上终于搞清楚了~~~~哇哈哈哈哈~~~好神奇哈哈哈哈哈~~~(疯了吧!) json.jsonp.jQuery Ajax这些东西说定义我也不是特别研究,只懂个大概,就不去复制百科了,没意思. 一.先说我要做的事情的需求,上来就撸代码估计很多人懵逼(就像今天下午的我一样- -||) 意图:本地服务端servlet生成json数据,我想在前端获取json数据并渲染成列表显

PHP获取HTML内容及动态渲染js加载内容

写爬虫的时候,使用guzzle异步并发的get请求真的好用,可以快速爬取,及时PHP不是多线程的,却能使用协程实现异步并发-用户态的多线程,也有时候,请求地址返回的页面很多待执行的JavaScript代码,数据需要动态渲染上去,这里有个简单的方法 就是使用querylist,用了这个扩展也可以不再依赖php的dom解析工具-simpledom,也自带了远程获取功能. 1.安装 安装querylist composer require jaeger/querylist 安装phantomjs co

获取简单的输入和渲染窗口(Hello Window)

我们可以使用GLFW的glfwGetKey方法来为我们绘制的窗口获取输入,这个方法返回值表示当前这个按键是否被按下.代码如下: void processInput(GLFWwindow *window) { if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); } 使用GLFW_KEY_ESCAPE表示ESC键位,其中ESCAPE可以被替换为其它键位.当ESC键没

ajax获取数据后怎么去渲染到页面?

关于,这个问题呢!一直没有在网上找到一个合适答案(可能这问题比较傻,嘿嘿).今天把自己常用几种方式说下: 第一种: 比较常见的就是直接把字符串拼接,然后插入到元素中. var html='<li>' + data.num + '</li><li>' + data.floor + '</li><li>' + data.name + '</li><li>' + data.money + '</li>'; elem.

给echart初始化的dom节点绑定时间获取点击的值渲染省市区

this.drawMap().on('click', function (params) { var province = params.name; that.mapStatus = province; if(province=="北京"||province=="天津"||province=="长春"||province=="长沙"||province=="杭州"||province=="昆明&q

用PHP获取网页上的信息相对于xpath效率低点

用php实现对网页的抓取,及信息的收集,其实就是爬数据,具体实现步骤如下,首先应引入两个文件curl_html_get.php和save_file.php文件,两个文件具体代码是这样的curl_html_get.php内代码为 <?php function curl_get_file_contents($url) { $c = curl_init(); curl_setopt($c, CURLOPT_RETURNTRANSFER, 1); curl_setopt($c, CURLOPT_URL,

在Ogre中直接使用D3D

使用Ogre时可以通过RenderSystem_Direct3D9直接访问D3D 直接使用D3D需要安装D3D SDK,典型的为2010 June SDK 需指定包含路径: C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include $(Ogre181)\include\OGRE 库路径: $(Ogre181)\lib\Debug\opt\RenderSystem_Direct3D9_d.lib C:\Program File

Ogre 渲染目标解析与多文本合并渲染

实现目标 因为需求,想找一个在Ogre中好用的文本显示,经过查找和一些比对.有三种方案 一利用Overlay的2D显示来达到效果. http://www.ogre3d.org/tikiwiki/tiki-index.php?page=MovableTextOverlay 二重写Renderable与MovableObject,利用对应字体查找到每个字符元素纹理坐标. http://www.ogre3d.org/tikiwiki/tiki-index.php?page=MovableText 三利

使用D3D渲染YUV视频数据

源代码下载 在PC机上,对于YUV格式的视频如YV12,YUY2等的显示方法,一般是采用DIRECTDRAW,使用显卡的OVERLAY表面显示.OVERLAY技术主要是为了解决在PC上播放VCD而在显卡上实现的一个基于硬件的技术.OVERLAY的出现,很好的解决了在PC上播放VCD所遇到的困难.早期PC处理能力有限,播放VCD时,不但要做视频解码工作,还需要做YUV到RGB的颜色空间转换,软件实现非常耗费资源,于是,YUV OVERLAY表面出现了,颜色空间转换被转移到显卡上去实现,显卡做这些工