由 创新网小编 于 星期五, 2014-04-11 14:56 发表

移动设备中的CPU和GPU已经变得很强大,到处都是配备一个或多个高分辨率屏幕的设备,需要使用带有图形驱动器的复杂交互也日益增加。在这篇博客文章中,我将讨论多线程和多窗口渲染对开发人员来讲意味着什么,同时我将介绍将这些技术应用您设计当中的条件和时机。

什么是多线程渲染?
传统上,OpenGL ES应用程序只从一个线程渲染到一个图层。然而,由于3D渲染引擎的复杂性有所增加,图形API操作的CPU开销已经成为瓶颈—尤其是加载资源时。这就使得多线程渲染引起关注。

渲染线程是与图形环境关联的CPU线程。默认情况下,每个图形环境将无法访问另一个环境中的资源(纹理、着色器和顶点缓冲区)。因此,需要使用共享环境,造成一个或多个后台负载线程可访问主线程的资源。这种渲染模式相当有效的原因有两个:

1. 主线程不会阻塞
从根本上说,一直到应用程序和驱动程序内存之间的传输完成之前,上传数据的图形API调用一定会被阻塞。此外,在许多显卡驱动程序中着色器编译就是阻塞型操作。这种阻塞造成开销较大,导致GPU无法运行。将所有上传操作迁移至后台线程,主线程可以维持统一帧率

在多核CPU上进行并行任务分配
由于图形驱动程序在CPU上运行,将这项运行分配至多个渲染线程,使得操作系统向多个CPU内核并行发布指令。这就导致与单个渲染线程相比,驱动程序的工作负载能够处理的更为迅速

使用多线程渲染?

OpenGL ES数据上传—未经优化

OpenGL ES数据上传—经优化

OpenGL ES数据上传—未经优化
多线程渲染最适合于编译着色器或上传数据至显卡驱动器时CPU资源有限的应用程序。多线程渲染(完成之后效果明显)能够更好地分配驱动程序的任务,并使得应用程序保持统一帧率。

上述简单示例当中,游戏当中从一级升至二级需要上传增加的纹理、 VBO和着色器程序。假设需要完成无缝升级(即启动画面、视频等无法降低上传开销) ,仍在渲染一级时游戏程序必须向驱动程序上传新资源。

在未经优化的情况下,向驱动程序发布调用指令时,由于增加了上传/编译操作负载,每帧所用时间并不一致。提交帧所增加的时间将会造成无法同步刷新,帧率不一致,会感觉游戏很卡。

经过优化的情况下,第二线程用于上传资源。这就使得主线程维持统一的调用递交时间,保证帧率一致。

最佳实践
在实现最佳性能时,应在启动程序时创建渲染线程。主线程应用于所有渲染。增加的线程(在共享环境中创建)应只用于着色器编译和缓存数据上传。后台线程的数量应保持在最低限度(如每个CPU内核一个线程) 。创建线程过多会导致难以维护,代码无法调试。

调用eglMakeCurrent()应保持在最低限度以降低开销(EGL specification规定在上下文一定要开启新线程之前,必须刷新所有未执行的操作)。

什么情况下不应使用多线程渲染?
不受CPU资源限制或不涉及加载次数时
如果运行显卡驱动程序时,CPU资源足够,就应该避免多线程渲染。它会增加渲染引擎的复杂性,如果处理得不好,甚至可能降低性能。

试图“简化”渲染引擎时
最糟的使用实例是不断将单一图形环境绑定至不同线程(使用eglmakeCurrent()) 。这样很糟糕,原因有两个:
The cost of context binding 上下文开销
正如以上所述,调用eglMakeCurrent()迫使驱动程序取消所有未完成的操作

API calls are serialized API调用串行化
由于图形环境在任何时点只能绑定到一个CPU线程,所有API调用将被串行提交

因此,API调用与单线程渲染的开销一致(API调用提交呈串行化),但上行文转换时需要额外开销......也就是说与单线程渲染相比,性能会较差

似乎这是较好的设计,但以这种方式渲染会导致代码复杂凌乱,提交顺序不清(甚至更难以调试! ) 。
不要这样做!

这是多窗口渲染?
多窗口渲染将一个应用程序渲染在多个窗口表面。通过操作系统窗口合成器(例如,Android系统的Surface Flinger或Linux发行版的X11)将这些窗口图层进行合成,以提交至设备屏幕。

在多窗口应用程序中,CPU线程和图形环境呈一对一映射。每个图形环境用于渲染到各自的窗口图层。
什么时候应该使用多窗口渲染?

多窗口渲染最适合用于应用程序需要渲染一个以上屏幕时,例如,当电视机作为第二屏时。
什么时候不应该使用多窗口渲染?

合成层

多层合成—未经优化

多层合成—经优化

在上述未经优化的实例中,在单个图层渲染游戏场景、触摸控件和迷你地图。应用程序利用操作系统合成器将这些图层组合成可以显示的图层。由于必须要为多个图层分配内存,因此这种方法较浪费资源,该合成器将处理未完全使用的透明像素和GPU的隐藏面消除(HSR),(即被不透明UI元素覆盖的片段冗余着色)

在经优化的情况下,游戏场景第一次渲染,然后触摸控件和迷你地图直接渲染于同一图层。在应用程序中FBO用于执行合成的情况下,这种方法并不适合。例如,游戏场景可以被渲染至较低分辨率FBO,将位图传输至应用程序窗口表面,UI元素可以按原始分辨率被驱动至顶点(这项技术通常用于在渲染游戏场景时增加每个像素的性能)

PVRTrace当中的多线程多窗口支持

自IMAGINATION发布 PowerVR Graphics 3.2 SDK以来 ,PVRTrace(OpenGL
ES捕获和分析工具)支持需要执行这些复杂图形驱动程序交互的应用程序。其中还包括Call View 和Frame
Selector中的每线程状态检查器、每线程过滤,线程使用时间轴图。所有这些功能组合使得多线程OpenGL ES更加便于调试。此外,我们的 PVRVFrameOpenGL ES模拟器的多线程支持已经得到显著改善。

自IMAGINATION发布 PowerVR Graphics 3.2 SDK以来 ,PVRTrace(OpenGL
ES捕获和分析工具)支持需要执行这些复杂图形驱动程序交互的应用程序。其中还包括Call View 和Frame
Selector中的每线程状态检查器、每线程过滤,线程使用时间轴图。所有这些功能组合使得多线程OpenGL ES更加便于调试。此外,我们的
PVRVFrameOpenGL ES模拟器的多线程支持已经得到显著改善。

结论
多线程多窗口渲染当中创建复杂难以调试的渲染引擎很容易您陷入困境。然而,如果使用正确也会帮助系统实现较多功能,提高灵活性。如果你按照本篇博客指南设计,将会提升资源负载的性能,而不会带来不必要的麻烦。
原文链接:
http://blog.imgtec.com/powervr/understanding-opengl-es-multi-thread-mult...

深度剖析OpenGL ES中的多线程和多窗口渲染技术的更多相关文章

  1. opengl es中不同的绘制方式

    opengl es中不同的绘制方式 转载请保留出处:http://xiaxveliang.blog.163.com/blog/static/297080342013467344263/ 1. GL_P ...

  2. OpenGL ES 中Uniform块

    1.采用uniform Block的原因如果你的程序中包含了多个着色器,而且这些着色器使用了相同的Uniform变量,你就不得不为每个着色器分别管理这些变量.Uniform变量的location是在程 ...

  3. 通过cocos2d-x的CCGLProgram和CCShaderCache的实现来分析OpenGL ES中的Shader编程

    在OpenGL ES中,Shader是着色器,包括两种:顶点着色器(Vertex Shader)和片元着色器(Fragment Shader).每个program对象有且仅有一个Vertex Shad ...

  4. OpenGL ES中MRT应用

    Demo涵盖了OpenGL ES 3.0 的一系列新特性: 1.VAO和VBO 2.帧缓冲对象 3.MRT 效果: 代码: //yf's version #define STB_IMAGE_IMPLE ...

  5. OpenGL ES 中的模板测试

    模板测试的主要功能是丢弃一部分片元,相对于深度检测来说,模板测试提出的片元数量相对较少.模板测试发生在剪裁测试之后,深度测试之前. 使用模板测试时很重要的代码提示: 1.glClear( GL_STE ...

  6. 深度剖析:PHP中json_encode与json_decode

    一.json_encode() 对变量进行JSON编码, 语法: json_encode ( $value [, $options = 0 ] ) 注意:1.$value为要编码的值,且该函数只对UT ...

  7. 深度剖析前端JavaScript中的原型(JS的对象原型)

          这张图片有点劝退了,哈哈哈~    通过原型机制,JavaScript 中的对象从其他对象继承功能特性:这种继承机制与经典的面向对象编程语言的继承机制不同.本文将探讨这些差别,解释原型链如 ...

  8. C语言深度剖析-----C语言中的字符串

    S1字符数组 S2字符串,存在于栈空间 S3最常规的写字符串的方法,malloc是堆空间,存在于只读存储区,我们不能够改变指向S3的数据 S4堆空间  S4 字符串的长度 判断字符串长度,assert ...

  9. OpenGL ES 如何能看到一个物体内部和象3dmax中能只显示网格线

    上一篇 OpenGL ES 正反面设置指令 中分析了正反面的判区方法,那么正反面有什么用呢?接下来我们就要引入一个叫做背面消除的概念.在3dmax中有个选项,当你用挤压修改器挤出一个中空的长方体时,在 ...

随机推荐

  1. nginx启动脚本(class练习)

    说明:使用类的方式编写程序启动脚本(练习) 1 #!/usr/bin/env python import sys import os from subprocess import Popen,PIPE ...

  2. POJ1220(大数进制转换)

    NUMBER BASE CONVERSION Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 4652   Accepted: ...

  3. Map占用内存大小评估

    public class test { private static java.util.HashMap<String, String> needQueryResProductList = ...

  4. Linux管道符、重定向与环境变量

    ——<Linux就该这么学>笔记 输入输出重定向输入重定向 指把文件导入到命令中输出重定向 指把原本要输出到屏幕的数据信息写入到指定文件中 输出重定向 分为标准输出重定向和错误输出重定向 ...

  5. 给tomcat单独配置jdk

    在catalina 文件 加这句话,前面加 export JAVA_HOME=/home/apache-tomcat-8.5.8/jdk1.8.0_101

  6. Asp.Net Core 项目实战参考

    Asp.Net Core 项目实战链接 http://www.cnblogs.com/fonour/p/5904530.html

  7. Java 的初始化顺序

    初始化顺序: 1.将对象内存空间初始化为二进制0(所有的数据成员被设为默认值) 2.如果该类有基类则初始化其基类(调用默认基类构造器,也可在子类构造器中指定调用基类的某个构造器) 3. 静态成员和静态 ...

  8. QPS、TPS、PV等网站业务关键字释义

    QPS:Query Per Second TPS:Transaction Per Second PV:Page View RT:Response Time UV:Unique Visitor DAU: ...

  9. 第六篇:远程过程调用(RPC)

    Remote procedure call (RPC) 客户端接口 有关RPC的说明 回调队列 消息属性 关联的ID ( Correlation Id ) 整合 在第二篇教程中,我们学习了如何使用工作 ...

  10. Android局域网访问webservice以及其中的一些问题

    应老师的要求,要做个安卓app,实现备份app上的数据到服务器上的mongodb上,网上搜了下相关的实现方式.利用webservice技术,具体来说就是客户端直接调用服务器端的接口.之前从来没接触这玩 ...