07. WebApp2.0时代启程:倒立者赢,从CPU到GPU,一张图片的旅行

紧接上文,终端开发使用的WindVane、wax、ReactNative等已经是一种跨平台的技术,我们称之为上层跨平台,Cocos2d-x这种直接使用C/C++,我们成为底层跨平台。上层跨平台,提升开发效率;下层跨平台,提升程序性能。

1. 为什么Cocos2d-x性能比Native开发要好?

因为Cocos2d-X是游戏引擎呗,人家是专业做游戏特效的好不好,直接调用GPU的OpenGL绘图的好不好。打开Cocos2d-X代码,感触最深的不是CCNode这些游戏节点,cocos2d-x已经开始为App开发做准备了!

大家看到了什么?UIImageView?UIScrollView?OMG!当我们还在纠结要不要学习一下游戏开发的时候,人家都已经开始做UI系统了,有木有!!

很长一段时间,我们以为Game和App之间有一种天然的鸿沟,长久以来,这两种技术之间没有直接的联系,App可以做各种UI控件,游戏可以做各种UI特效,当游戏开发者想NativeApp大步的走过来的时候,我们还在学习如何用UITableView去优化图片的显示,岂不知在游戏世界里,早已实现了图片的异步加载、解码、缓存了!

别忘了,从iOS7.0开始,苹果已经默认集成了GameKit.framework,颤抖吧!游戏和App即将面临傻傻分不清楚的时候了。

2. 一张图片在OpenGL的世界里,是如何从SDCard显示到屏幕

这一次,我们不是讲UIImage如何加载一个图片,而是自己读取图片文件,解码图像,上传纹理,推送顶点缓冲,刷新帧缓冲,一步步显示图片到屏幕上。

上图之前,我们先了解几个概念:
2.1 帧缓冲:
我们要显示的视图绘制到屏幕上,本质是一个int32 buffer[width x height x 4]的一个数组,不管2D还是3D,我们都要吧GPU的对象投影到这个buffer中,一个像素4字节表示[R/G/B/A]。

2.2 顶点缓冲:
终端设备,只支持精简版的OpenGL,称之为OpenGL ES,这里我们只用2.0版本。在这个版本中,我们只能画三角形,一个正方形的图片纹理,需要两个三角形才可以描述:

我们要画图片之前,就要告诉OpenGLES图片顶点的位置,先忽略三角形的顺序问题,就这样告诉GPU:【ABDBDC】,同时设置当前的激活的纹理,就可以绘制图片了。

2.3 上传纹理:
现在绝大多数手机,都有独立的显卡芯片,每个显卡芯片都有独立的显存,这么就清楚了:我们常说的内存是CPU直接操控的内存条容量,算上显存,就有两个缓存空间了,程序员可以发挥的空间又多了,是不是有点小激动?

2.4 图片解码:
常见的jpg、png等图片文件,都是压缩后的文件,如果不压缩,一张1024x1024的图片,至少需要4M空间。一张图片文件解码到内存,需要解码器来解码,不幸的是,Android很多机型没有集成硬件解码,庆幸的是iOS设备内部支持硬件解码。如果一张图片文件可以瞬间在底层硬件解码完成,要比上层代码优化,更加直接!这就是我们为什么一直追求的是底层跨平台的原因。

2.5 讲了很多概念了,我们上图吧

3. 原来图片可以不占用内存!

我们用C的API来读取一张图片,用libpng来解码一张png图片,调用OpenGL ES2.0API上传图片到GPU显存,指定绘图坐标,显示一张图片,我们上代码吧:

一)读取文件:

AEFileData AEFileDataWithPathfile(std::string& pathfile) {
    AEFileData data;
    FILE* file = fopen(pathfile.c_str(), "rb");
    if (file == NULL) {
        return data;
    }
    fseek(file, 0, SEEK_END);
    data.size = (GLuint)ftell(file);
    fseek(file, 0, SEEK_SET);
    data.bytes = (GLchar)malloc(sizeof(GLchar)  data.size);
    fread(data.bytes, sizeof(GLchar), data.size, file);
    fclose(file);
    return data;
}

二)解码图片:
为了跨平台通用,我们用libpng来解码图片,获取png的format和rgba数组,【代码太多,就不贴了】

三)上传GPU:

glGenTextures(1, &_textureId);
glBindTexture(type, _textureId);
glTexImage2D(type, 0, _format, _size.width, _size.height, 0, _format, GL_UNSIGNED_BYTE, pixels);

四)释放内存

AEFileData file = AEFileDataWithPathfile(pathfile);
this->initPNG((GLuchar*)file.bytes, file.size);
__FREE(file.bytes);

五)指定顶点索引,并绘制

vb[0] = {d11, t11, color};
vb[1] = {d21, t21, color};
vb[2] = {d12, t12, color};
vb[3] = {d21, t21, color};
vb[4] = {d12, t12, color};
vb[5] = {d22, t22, color};
glDrawArrays(GL_TRIANGLES, 0, _vertexIndex);

4. 对比iOS与Android,图片的渲染和展示做了什么?


Android的技术框架更偏于上层,看不到底层C/C++代码实现,优化的空间有限;Objective-C更靠近C语言,优化的空间明显。下面我们以iOS为例:

5. 主流框架的图片优化思路

要读懂图片的展示与优化,就要看看当前主流的图片优化框架,他们是如何做优化的?主流的ImageCache框架:SDWebImage/FastImageCache/TBImageCache

左边的是SDWebImage,中间是FastImageCache,右边是TBImageCache

SDWebImage:
将解码后的图片分别保存到内存和SDCard,将复杂的操作放到了子线程中;

FastImageCache:
直接将文件读取到mmap映射的文件中,减少了一次从系统内核到用户空间的一次拷贝【然并卵】

TBImageCache:
在首次加载图片时,根据用户需要,对图片增加圆角阴影处理,增加了异步线程的处理的工作量,同时保存到sdcard中,消耗了额外的资源,换取的是更好的图片性能【解决了圆角阴影在终端的痛点】

图片缓存框架,只是让CPU负载曲线更均衡,有没有可能再进一步优化?

6. 游戏世界与App世界对比

CPU与GPU是终端的双驾马车,缺一不可,CPU load过高,导致终端卡顿,同理GPU也是如此。iOS的UIKit框架封装的太好了,也是优化做的最好的,让我们看不到底层的原理,看不到iOS是如何平衡CPU、GPU、RAM、GPU RAM的4者之间的关系,让我们大胆大猜测一下吧:

一)UIImageView管理者UIImage对象
UIImage就是内存中得bitmap数组,当我们需要绘制一张图片的时候,CPU发出指令,上传BitMap到GPU的显存中,GPU返回生成的纹理ID给CPU。

二)为了提高iOS的性能,苹果做出了一个优化策略,不释放CPU的bitmap
当GPU显存空间不足的时候,iOS会释放一部分图片纹理,以节省显存空间,但不会释放内存的bitmap。当一张图片重新需要绘制的时候,iO快速从内存bitmap快速上传到显存,完成绘制过程。

三)当内存的bitmap释放的时候,同步释放显存的纹理对象
本质意义上说,bitmap在内存中得存储,不是真正显示的那个缓存,当bitmap上传到GPU的时候,GPU会在显存中申请同样大小的空间,来存放bitmap,并返回纹理ID,每当CPU需要显示某张图片的时候,只需要高速GPU要绘制那个纹理ID就可以了。

四)上传GPU后,我们完全可以释放内存bitmap
释放内存的bitmap很简单: free(bitmap);
这样内存里只剩下了对应的GPU纹理的ID,当GPU内存紧张的时候,程序要要自己释放不需要的纹理ID,如果这个ID在某个时候有需要使用了,怎么办?那要把之前的读取文件到上传GPU重走一遍,太耗性能了,我想苹果也是不想看到这个原因,才不会轻易释放bitmap的

总结:游戏的架构模式,需要开发者自己优化所有场景

游戏开发者不仅需要优化CPU内存,也要优化GPU内存,通过将所有图片合成一张大的纹理图片,来统一管理GPU内存,需要把大量浮点数运算根据不同的场景,或者交给CPU或者交给GPU,让CPU和GPU的负载达到均衡,各司其职。
这一些优化,对于我们做系统上层应用的无线开发,是很难想象有多少坑等着我们,终端App的开发,还是使用上层框架好,图形图像的世界水很深,有想法的同学,可以继续关注下一章分享,想了解我们的同学,可以用Android下载安装我们的Demo:

下一章,我们一起见证所及即所得的开发方式,WebApp2.0初体验

时间: 2024-12-01 18:57:43

07. WebApp2.0时代启程:倒立者赢,从CPU到GPU,一张图片的旅行的相关文章

08. WebApp2.0时代启程:倒立者赢,NativePixi,所见即所得的开发方式

紧接上文,在终端设备中,不管是游戏引擎还是UIKit,图形图像都是基于跨平台的OpenGL ES技术,区分不同的场景,图形图像分为两个分支,一个以高性能的图形显示为目标的cocos2d-x引擎,一个是以省电节能适合App的UIKit框架. 一)今天我们继续逆向思维 Game VS App,既然都是基于OpenGL ES,那我们找出共同点,是否可以让二者的界限,变得更模糊?既可以满足高性能的Game引擎,可以保持App开发? 请仔细观看上图,我们的框架多了一个WebKit? 对的,我以为WebKi

05. WebApp2.0时代启程:倒立者赢,从过去到现在的变化,看将来的发展(一)

1. 移动互联网的兴起,我认为2009年是个分水岭. 开始的时候,我也是做Java开发,习惯了Webx架构,可以熟练的使用Spring.iBatis.veloctiy.HSF.Notify.Tair.Session这些阿里具有代表性的Java框架,也会使用IC.UIC.SC.DC等等服务集群做电商核心业务.概括起来,基本也是三层服务端架构: 2. 技术架构也非常稳定 后台MySQL分库分表.服务端HSF业务处理,前端浏览器使用Html做展示,技术人员的重叠率较低,公司内部资源达到了最大化价值体现

09. WebApp2.0时代启程:倒立者赢,挑战Android性能极限

紧接上文,在终端硬件资源有限的大背景下,业务脚本+图形内核,将是未来主流的开发方式.AEPixi使用C/C++.JS.JNI.OC等混合语言开发,将pixi.js变成高性能的Native内核,提供上层pixi.js标准的API,无缝的兼容浏览器开发好的代码,实现浏览器开发,无需编译,到处运行的开发方式. 今天我们做一个H5的Demo,使用FireFox开发,开发完成之后,直接使用上一章节我们发布的android app,直接访问查看效果. 一)搭建前端开发环境 Subline Text2 / V

01. WebApp2.0时代启程:Cocos2d-JS详解(一)

(一)WebApp时代,追求App开发效率的同时,我们也要求终端的体验和性能,2/8原则可以很好的阐述当前的hybird开发方式:20%的Native代码+80%的H5代码. (二)H5可以发挥的性能极致是什么样子? 了解这个问题,就需要知道H5的技术定位:一套H5代码支持Android.iOS.PC等多平台的前端语言,这就决定了再好的iOS平台性能,也不能忘记Android平台的用户体验:最终开发者选择了降低用户体验情况下,降低了H5的用户体验. (三)H5可以做的更好,不管是Android还

03. WebApp2.0时代启程:Cocos2d-JS让C++代码支持JS脚本(三)

紧接上文,JS在单线程下,性能不会比Java差,注意场景是单线程.Java的优势不仅是高级语言的特性,还具备了丰富的系统内核资源,如多线程.网络等支持,要比JS灵活的多很多,这里暂时不在讨论这些问题. 回到主题,如果我们把一个完整的C++图形引擎注入到SpiderMonkey中,把复杂的预算放到C/C++内核中,而JS只作为业务处理和内存管理,是否可以获得C/C++的运行能力,有获得了良好的逻辑处理呢? 答案是肯定的!我们直入主题,我们使用最新的SpiderMonkeyV1.8.5,一起解析一下

02. WebApp2.0时代启程:Cocos2d-JS为什么选择SpiderMonkey(二)

紧接上文,cocos2d-JS为我们提供了图形引擎.物理引擎.JS引擎等基础库,在多终端时代提供了非常nice的游戏引擎,在浏览器普及在各个终端的今天,为什么还要单独搞一套JS引擎呢? 我们先看看使用SpiderMonkey的技术产品有哪些? 没有看错,SpiderMonkey就是FireFox浏览器的JS虚拟机(后续简称jsvm),FireFox的实力也是赢得了众多前端开发者的芳心:cocos2d-x更是不用说了,东亚97%的2D游戏开发者的选择,手游开发者的入门技能,k-3D也是在AEPIX

赢者通吃的数字广告2.0时代

每天我们使用各大互联网公司的各项服务:微信,微博,淘宝,Google -- 基本上,我们是不用为此付费的.但商业公司显然也不是慈善机构,广告商帮我们付了这笔账.对此,在互联网上流传着这么一句真理:当你是免费用户,那么你也是产品的一部分. 什么意思?即,免费用户是产业公司变现的工具.商业公司不可能无条件为人民服务,他们的带宽成本,运营成本及人力成本如果不由用户直接承担,那大抵是由广告商承担,顾客需要付出的就是注意力,时间甚至隐私.对于这句话的理解,商业公司们理应更加深刻,但很多公司做的远远不够.

全面迎接.Net3.0时代的到来(WCF/WF/WPF/LINQ)

全面迎接.Net3.0时代的到来(WCF/WF/WPF/LINQ) .Net3.0从2006年发布预览版到今天(最高版本已经达到.Net3.5了),已经日趋稳定,.Net2.0做为3.0/3.5的一个子集继续被支持,但3.0又引入了很多激动人心的新特性(虽然这些特性在业内早已在其它说来语言上实现,但MS的优势在于,将别人的优势融入自己的产品体系后,将变得更强大优秀) 这里介绍几个部分新特性: (一).LINQ的支持 经过了最近 20 年,面向对象编程技术( object-oriented (OO

总结Web2.0时代最关心的话题

中介交易 SEO诊断 淘宝客 云主机 技术大厅 Web2.0影响了个人和企业 以门户为王的Web1.0时代,互联网对于网民而言更多的是一种工具,电脑对于白领是台打字机.对小孩是台游戏机;互联网对于企业就是张内容.形式不受限制的名片,对于个人也就是个浏览新闻.打字游戏的家用电器.到如今这个革新中的Web2.0时代,人们将越来越多地因为Web2.0,而改变自己的生活方式.Web2.0最初是相对与传统门户提出的概念,它更多代表一种以用户为中心的服务理念.而不仅仅是技术,以博客的广泛应用为代表,每个人都