Updates from 九月, 2013 Toggle Comment Threads | 键盘快捷键

  • Roger 9:37 am on September 2, 2013 固定链接 | 回复
    Tags: , , , , , uc   

    High Performance Canvas Game for Android 

    UC在今年5月份发布了支持硬件加速的实验室版,开始实验性地支持对2D Canvas进行硬件加速。在9月份发布的9.3版本中开始分开两个版本 – 普通版和加速版,针对中高端手机的加速版开始正式支持硬件加速2D Canvas渲染。并且在未来将要发布的9.4加速版还会带来全新的Canvas渲染架构,进一步提升性能和减少对系统资源的占用。
    这篇文章的主要目的是为移动Canvas游戏的开发者如何针对Android UC浏览器9.4加速版进行渲染性能优化提供指导,不过文中的大部分内容也适用于Android平台其它支持硬件加速2D Canvas的浏览器,比如Chrome for Android。另外,这篇文章的内容主要是针对渲染性能优化,而不是JavaScript性能优化,不过因为Android UC浏览器使用的是V8引擎,所以您应该很容易找到很多如何针对V8优化JavaScript性能的文章。

    Rule #0 为移动平台进行优化

    为移动平台进行优化是十分重要的,因为移动平台的性能大概只有桌面平台的1/10左右(*1),它通常意味着:
    1. 更慢的CPU速度,这意味着不经过优化的JavaScript代码,性能会十分糟糕;
    2. 更小的内存,没有虚拟内存的支持,这意味着加载太多的资源容易导致内存不足,JSVM更容易引发GC,并且GC造成的停顿时间也越长;
    3. 更慢的GPU速度,没有独立的显存,内存带宽相比PC要慢的多,这意味着即使使用GPU对Canvas进行加速,您仍然需要小心网页DOM树的复杂度,游戏所使用的分辨率(Canvas的大小),图片资源的分辨率,游戏场景的复杂度和尽量避免Overdraw等等;
    注释:
    1. 如果您需要对移动平台浏览器的性能有一个全面的了解,建议阅读文章“Why mobile web apps are slow”(原文译文)和”5 Myths About Mobile Web Performance“(原文译文)。

    Rule #1 为Android而不是iOS而优化

    牢记这一点非常重要,Mobile Safari的Canvas渲染机制跟Android平台有很大的不同,特别地针对Mobile Safari进行优化的Canvas游戏在Android平台的渲染性能会十分的糟糕。
    Mobile Safari使用了iOS/MacOS平台特有的IOSurface作为Canvas的Buffer,当通过Canvas API往IOSurface绘制内容的时候是没有GPU加速的,iOS仍然使用CPU进行绘制,但是将一个IOSurface绘制到另外一个IOSurface上的时候,iOS会使用GPU的2D位拷贝加速单元进行加速(*1)。这种机制其实也是iOS UI界面Layer Rendering渲染架构的基础。所以为iOS优化的Canvas游戏会倾向于使用大量的Off-Screen Canvas(*2),不管是静态的图片也好,还是需要动态产生的内容也好,统统都缓存到一个Off-Screen Canvas上,最终游戏场景的绘制就是一个把一堆Off-Screen Canvas绘制到一个On-Screen Canvas的过程,这样就可以充分利用iOS绘制IOSurface到IOSurface使用了GPU加速的特性来提升渲染性能。
    但是这种大量使用Off-Screen Canvas的做法在Android平台的浏览器上会非常糟糕。Android平台并没有IOSurface的同等物(一块同时支持CPU读写和GPU读写的缓冲区),所以它只能使用GL API对Canvas进行加速,一个加速的Canvas,它的Buffer是一个GL Texture(被attach到一个FBO上),这意味着:
    1. 无论是绘制到Canvas本身,还是Canvas绘制到Canvas都是GPU加速的,普通的位图要绘制到Canvas上,需要先被加载到一个Texture中;
    2. Texture Buffer只能通过GPU进行读写,如果要使用CPU访问,必须先通过glReadPixels把内容从显存拷贝到一块普通内存,而这个操作会非常慢并且会造成GL渲染流水线的阻塞;
    3. 如果游戏频繁创建和销毁一些比较小的Canvas,会很容易造成显存的碎片化,让显存的耗尽速度加快,并且创建太多的Canvas也容易把GPU资源都消耗光,导致后续的分配失败和渲染错误;
    4. 当每个Game Loop都对多个Canvas进行同时更新时,会导致GL Context不断地切换不同的Render Target(FBO),而这对GL的渲染性能有很大的影响;
    后续的内容会进一步说明如何针对使用GL加速的Canvas渲染架构进行优化。
    注释:
    1. 一般GPU都会带有多个独立的加速单元,包括3D加速单元,支持GL和D3D这样的3D API;2D位拷贝加速单元,对将一块缓冲区绘制到另外一块缓冲区进行加速;2D矢量绘制加速单元,支持像OpenVG这样的2D API,但是Android平台只支持通过GL API使用GPU加速,并没有公开的2D位拷贝加速API,虽然2.x的时候厂商可以提供一个copybit模块对位拷贝进行加速,供SurfaceFlinger使用,但这个模块不是通用的,并且不对外公开,另外在4.x的时候也已经移除了。
    2. Off-Screen Canvas在文中是指display:none,没有attach到DOM树上的Canvas,相对于On-Screen Canvas而言。

    Rule #2 优化网页的DOM树结构

     

    Canvas只是网页的一部分,它最终要显示出来还需要浏览器对网页本身的绘制,如果网页的DOM树结构越复杂,浏览器花在网页绘制上的时间也就越长,网页绘制占用的CPU/GPU资源也就越多,而留给Canvas绘制的CPU/GPU资源也就越少,这意味着Canvas绘制本身需要的时间也越长。并且网页绘制的耗时越长,Canvas最终更新到屏幕上的延迟也就越长,总之,这是一个此消彼涨的过程。所以,优化网页的DOM树结构,让其尽可能简单,浏览器就可以把更多的系统资源花费在Canvas的绘制上,从而提升Canvas的渲染性能。

     

    最理想的DOM结构就是只包含一个<body>,加上一个<div>作为容器和加上一个<canvas>本身。如果Canvas上面需要显示其它的网页内容,最好只是用于一些临时使用的对话框之类的东西,而不是一直固定显示。

     

    Rule #3 优化网页元素的css背景设置

     

    跟#2的道理一样,背景设置越简单或者根本不设置背景,浏览器花费在网页本身绘制的开销也就越小,一般来说<canvas>元素本身都不应该设置css背景,它的背景应该通过Canvas API来绘制,避免浏览器在绘制<canvas>元素时还要先绘制背景,然后再绘制Canvas的内容。另外<body>和其它元素都应该首先考虑使用background-color而不是background-image,因为background-image的绘制耗时比一个纯色填充要大的多,而且背景图片本身还需要消耗额外的显存资源(生成Texture)。

     

     Rule #4 使用合适大小的Canvas

     

    考虑移动设备的性能限制,Canvas不适宜太大,否则需要消耗更多的GPU资源和内存带宽,480p或者600p是一个比较合适的选择(横屏游戏可以选择800p或者960p),一般不应该超过720p。并且游戏图片资源的分辨率应该跟Canvas的分辨率保持一致,也就是正常情况下图片绘制到Canvas上应该不需要缩放。

     

    我们需要避免创建了一个较大的Canvas,但是仍然使用较低分辨率的图片资源,图片绘制到Canvas上还需要经过缩放的情况。这样做毫无意义,因为游戏本身的分辨率是由图片资源的分辨率来决定的,上述的情形既不能提升游戏的精美程度,也白白浪费了系统资源。

     

    如果自己预先指定了Canvas的大小,又希望Canvas在网页中全屏显示,可以通过<meta viewport>标签设置viewport的大小(*1,*2),直接告诉浏览器网页虚拟viewport的宽度应该是多少,并且让viewport的宽度等于Canvas的宽度,而浏览器会自动按照viewport宽度和屏幕宽屏的比值对网页进行整体放大。

     

    注释:
    1. <meta viewport>的设置可以参考这个例子:http://www.craftymind.com/factory/guimark3/bitmap/GM3_JS_Bitmap.html
    2. Android系统浏览器在网页不指定viewport宽度时,它会认为这是一个WWW页面,并且使用980的默认viewport宽度,UC浏览器也遵循了同样的做法。这意味着您不设置viewport宽度,并且直接使用window.clientWidth作为Canvas的宽度时,就会创建出一个980p的Canvas,通常这是毫无意义的;

     Rule #5 避免使用多个On-Screen Canvas

    如#1所述,多个Canvas同时更新会降低GL渲染的效率,并且如#2所述,多个On-Screen Canvas会导致网页本身的绘制时间增加,所以应该避免使用。

    Rule #6 合理地使用Off-Screen Canvas

    在GL加速的Canvas渲染架构下,合理地使用Off-Screen Canvas可以在某些特定的场景提升渲染性能,但是不合理的使用反而会导致性能下降。
    1. 将图片绘制到一个Off-Screen Canvas上,然后把这个Canvas当作原图片使用,这种用法,如#1所述,在iOS上是有用的,但是在Android上不必要的,甚至会导致额外的资源浪费(虽然渲染性能还是一样)。浏览器会自动将需要绘制到Canvas的图片加载成Texture并缓存起来,避免反复加载,只要这个缓存池大小没有超过限制,图片的绘制就只需要付出一次贴图的开销,这对GPU来说是很小的;
    2. 避免使用过大或者过小的Off-Screen Canvas —— 首先过大的Canvas会超过系统的Max Texture Size而无法进行加速(*1,*2),而太小的Canvas(*3,*4),因为对它加速不但不会加快渲染速度,反而会导致如#1所述的一些问题 —— 加快GPU资源的耗尽,频繁切换Render Target的额外开销等,所以也是不加速的;
    3. 避免频繁动态创建和销毁Canvas对象,这样很容易引发GC,而且浏览器为了避免大量的Canvas Buffer把GPU资源耗尽,还会在接近临界值时进行强制GC(*5),而强制GC造成的停顿比一般GC还要长,通常会达到500ms~1000ms。所以一般来说应该事先生成所有需要的Canvas然后一直使用,或者建立一个缓存池来回收和重用;
    4. Canvas初始大小设置后就不应该再改变,否则浏览器需要为它分配新的Buffer;
    5. 需要动态生成的内容,可以在一个Off-Screen Canvas上预先生成,然后直接将这个Canvas绘制到On-Screen Canvas上,但是这个生成应该是一次性的(或者偶尔),而不是每个Game Loop都需要更新,否则就会造成#1所述的问题 —— 频繁切换Render Target的额外开销;
    6. 如果场景中的部分内容很少发生变化,但是位置,缩放比例,旋转角度,透明度等属性需要频繁变化,可以把一个Off-Screen Canvas当作Layer使用,缓存这部分内容,然后在绘制这部分内容时就直接绘制这个Off-Screen Canvas;
    总结一下,Off-Screen Canvas的使用应该尽量遵循以下原则:
    1. 数量适中(越少越好);
    2. 大小适中(面积128×128以上,长宽2048以内,并且为2的幂次方对GPU来说是最友好的);
    3. 一次创建,大小固定,持续使用;
    4. 读多写少(可以在每个Game Loop都绘制到On-Screen Canvas上,但是自身更新/变化的次数应该很少,避免每个Game Loop都更新);
    注释:
    1. 一般手机的Max Texture Size是2048,高端的机器可能会到4096或者8192,Canvas长宽任意一边超过这个大小都无法使用Texture做为自己的Buffer;
    2. 非加速的Canvas仍然使用普通的Bitmap作为自己的Buffer,这意味着它的绘制仍然使用CPU,并且它绘制到另外一个Canvas还需要先加载成Texture,而加速的Canvas本身就是一个Texture,所以它绘制到另外一个Canvas上只需要一次贴图的开销;
    3. WebKit默认的设置是128×128大小以内的Canvas不加速,UC和Chrome都使用了默认的设置;
    4. 把一个比较大,加速的Canvas绘制到一个比较小,不加速的Canvas会非常非常慢,这是因为浏览器需要从显存拷贝内容到普通内存,拷贝的速度很慢并且会造成GL渲染流水线的阻塞;
    5. 一个小技巧是,如果一个Canvas不再使用,可以将它的长宽设置为0,这样在JSVM的垃圾收集器还没有回收该Canvas对象时,浏览器就可以先释放它的Buffer,这样可以避免浏览器因为Buffer占用太多而不得不强制GC,不过总的来说最好还是自己建立缓存池;

    Rule #7 避免频繁调用getImageData,putImageData和toDataURL

    因为它们都会需要从显存拷贝内容到普通内存,或者相反,拷贝的速度很慢并且会造成GL渲染流水线的阻塞。所以不要在每个Game Loop都调用这几个API。

    Rule #8 如果需要最大帧率,优先使用requestAnimationFrame而不是Timer

    如果您的游戏只需要20或者30帧,那么就只能使用Timer。但是如果希望达到设备本身的最大帧率,则应该使用rAF,因为rAF可以让浏览器把网页绘制,Canvas绘制跟屏幕刷新保持同步,减少Canvas更新的延迟,并且在网页不可见的时候还可以自动停止rAF回调,避免无谓的浪费电池。

    Rule #9 图片资源大小应该对GPU友好

    1. 避免使用太多小图片,而是应该把它们拼接成一张大图;
    2. 拼接的图片长宽应该是2的幂次方,并且小于或者等于2048,512×512,1024×1024都是不错的选择;
    3. 拼接的图片应该尽量避免留下大量空白区域,造成无谓的浪费;
     
    • shuyong 8:43 下午 on 四月 13, 2014 固定链接 | 回复

      好文章。以后写的一些文档会参考这里的观点。

      不过这个文章有一个小遗憾。在“Rule #1 为Android而不是iOS而优化”中有一句:
      “Android平台并没有IOSurface的同等物(一块同时支持CPU读写和GPU读写的缓冲区)”

      这里虽然没有错,因为ANDROID平台确实没有提供现成的off-screen nativewindow / nativewindowbuffer。但是应用程序其实是可以自己实现相应的off-screen window / buffer的。这需要思维上有点突破,把自己当成是system engineer,而不只是application engineer。多看一些其它项目,理解interface / implement,就会有新的天地,新的想法了。

    • Roger 10:21 上午 on 四月 14, 2014 固定链接 | 回复

      实际上Android 的 GraphicBuffer 有类似的作用,也可以被应用所使用,但是它有很多限制,不如IOSurface那么灵活,并且不同SoC上的兼容性问题很严重,所以在实际使用中只能用于特定的场景。

      另外不明白这里跟system engineer有何关系,浏览器毕竟不是OS本身,它需要运行在各种不同的硬件/系统版本上,浏览器自身是没办法绕过硬件/系统本身的限制的,除非像Chrome OS/Firefox OS那样。

      • shuyong 11:40 下午 on 四月 14, 2014 固定链接 | 回复

        所谓system engineer,就是有一点可能性,就会尝试实现。Chrome / Firefox也是逐步总结出抽象的移植层,在各个平台上,保证上层都有相同的特性,又要保证可移植性。如果在某个平台没有底层支持,那就实现一个。最终就是要保证上层都有相同的特性。而上层的特性足够多了,足够稳定了,自然而然就想进化到Chrome OS/Firefox OS了。

        我不了解IOSurface,所以对比不了灵活性。但是我做过测试,Android 的 GraphicBuffer应该有足够的稳定性和兼容性,不论是直接调用系统原生的,还是我自己重新实现的。我从Android 2.3到4.3,硬件平台有高通,NVIDIA,FREESCALE,TI,SUMSANG。国产的芯片的系统好像也测过几个版本。GraphicBuffer的接口已经足够稳定,特性也有足够的一致性,否则ANDROID就很难移植和运行了。

        如果自己实现一个off-screen ANativeWindow,通过重载dequeueBuffer / queueBuffer,应该很容易实现CPU / GPU之间访问内存的ZERO-COPY算法的。

        • Roger 9:45 上午 on 四月 15, 2014 固定链接

          如果你了解Chrome,就知道Chrome在Canvas上的实现更保守(或者也可以说是通用)和低效… 所以你既然没有真正了解Chrome的实现,就别在这里乱讲了…

          Android本身对GraphicBuffer的使用比较简单,NativeWindow是Double/Triple Buffering的机制,不存在需要CPU/GPU “同时” 读写同一块Buffer的状况,而Canvas是必须Single Buffer的。如果你测试过Nvidia的芯片,就应该知道Tegra是不支持CPU/GPU “同时” 读写同一块Buffer的,如果一个GraphicBuffer已经通过EGLImage binding到一个Texture上,再试图去unlock它,在Tegra的芯片上就会陷入死锁,高通的Adreno 2xx也有类似问题,Adreno 3xx虽然支持,但是Unlock/Lock一次的开销在3~7ms之间…

  • Roger 6:26 pm on May 20, 2013 固定链接 | 回复
    Tags: ,   

    New Graphics Improvement in Android 4.3 

    下一个版本的Android,姑且认为是4.3,图形性能会有哪些提升?Android团队的图形专家Chet Haase和Romain Guy在Google IO 2013的演讲Android Graphics Performance上为我们透露了部分信息,演讲的内容包括架构性能提升,性能分析工具的改善和应用优化的一些建议,本文根据演讲内容写成,希望对做Android图形性能研究的朋友有所帮助。

    参考链接

    Android Graphics Performance – YouTube:
    Android Graphics Performance – Slides:
    Why your Android Apps Suck:
    我的这篇文章对Android图形子系统做了一个基本分析,和对其架构做了对比和评价,可以作为后续内容的背景知识。
    Android DisplayList 机制浅析:
    这篇文章简单分析了Android DisplayList的机制。
    如何使用systrace做性能分析:
    介绍了性能分析工具systrace的使用。

    架构性能提升

    绘图指令重排和合并

    Android 4.3会对UI界面的绘图指令进行重新排列并且对同类型的绘图指令进行合并,从而减少对GPU发出的glDrawXXX命令的个数和避免频繁改变GL绘图流水线的状态(比如切换不同的Shader等等),最大化利用GPU加快绘图速度。

    p1

    演讲中演示了一个例子,上图的UI界面包括两个Checkbox的Icon和文本,两个Button的9-patch背景和文本,如果只是按照界面本身的UI组件排列顺序,绘制的顺序应该是:

    p2

    1,绘制Checkbox Icon
    2,绘制Checkbox文本“Include metadata”
    3,绘制Checkbox Icon
    4,绘制Checkbox文本“Maximize compatibility”
    5,绘制Button的9-patch背景
    6,绘制Button文本“Save”
    7,绘制Button的9-patch背景
    8,绘制Button文本“Cancel”

    上面的绘制包括8个绘图指令和7次Shader的变化。

    经过重新排序后,变成:

    p3

    1,绘制Checkbox Icon
    2,绘制Checkbox Icon
    3,绘制Button的9-patch背景
    4,绘制Button的9-patch背景
    5,绘制Checkbox文本“Include metadata”
    6,绘制Checkbox文本“Maximize compatibility”
    7,绘制Button文本“Save”
    8,绘制Button文本“Cancel”

    优化后的绘制包括8个绘图指令和2次Shader的变化。

    经过合并后,变成:

    p4

    1,绘制两个Checkbox Icon
    2,绘制两个Button的9-patch背景
    3,绘制四个文本

    进一步的优化后的绘制只需3个绘图指令和2次Shader的变化。

    多线程绘制

     p5

    首先要说明的是,Android GUI框架的线程架构并没有变,一样还是在主线程进行绘制(在主线程绘制而不是单独的渲染线程的弊端可以参考我的文章Why your Android Apps Suck)。只是一些比较耗时的渲染,比如Shadow和Path Effect的生成,可以通过多线程并发加快速度而已,具体线程的数目跟CPU的核心数有关。

    支持非矩形裁剪

    p6

    HW Canvas终于支持非矩形裁剪了,不过考虑到兼容性问题,估计也没人敢用……

    开发者工具

    p7

    Overdraw显示其实4.2就已经有了,对了解自己的应用是否过度绘制的开发者来说还是相当有用,最理想的情况是没有任何Overdraw,每个区域的像素只需要一次绘制,蓝色代表一次Overdraw,这意味着蓝色区域的像素被绘制了两次,绿色是两次,红色是三次,深红色是四次。当然实际上一次或者两次Overdraw很难完全避免,特别是界面包含一些复杂组合和半透明混合的效果,不过开发者可以通过这些信息来分析哪些Overdraw实际上是可以避免的,最后的优化建议环节Chet Haase和Romain Guy也通过一个实际的例子来演示一个应用如何对Overdraw进行优化。

    p8

    gfxinfo可以输出最近120帧绘制的耗时信息,其中Draw表示DisplayList生成的耗时,Process表示DisplayList执行的耗时,Execute表示窗口swap buffers的耗时,新的版本支持直接显示这些信息在应用的窗口上,这样就更加方便了。

    p10

    systrace在新的版本支持直接启动,不需要事先到开发人员选项里面去设置,并且公开了Java API供开发者分析自己的方法(其实4.1和4.2的版本也可以调用非公开的API)。
     
  • Roger 1:20 pm on April 20, 2013 固定链接 | 回复
    Tags: , , , ,   

    国内Android手机浏览器内核未来竞争势态分析 

    前几天跟主管谈到这个话题,讨论得出一些结论,记录下来以备将来验证。国内手机浏览器在所谓“自有内核”的竞争上将会分为两个不同阶段,目前处于第一阶段。

    第一阶段是基于WebKit开发的“自有内核”,大概有两种方式,一种是WebKit内核代码(WebCore部分)直接跟主干保持同步,定期更新,平台适配层架构基本跟Android系统浏览器的适配层架构保持一致,将大部分系统浏览器适配层代码移植过来;另外一种就是直接全部采用Android系统浏览器的代码,包括适配层代码和WebKit内核代码,然后WebKit内核代码再逐步向主干靠拢(Android系统浏览器包含的WebKit内核代码版本比较旧);当然这两种方式发展到一定程度,其实是殊途同归的,相对来说,第一种方式对团队的整体水平要求更高一些。

    这一阶段的主要玩家就是UC和腾讯,百度也有参与,但是它的移动战略实在让人看不懂,感觉十分摇摆不定,按理说百度人和钱都不缺,但是始终没有下定决心大幅度投入手机浏览器领域,不知道在第二阶段是否会改变策略。

    其它国内桌面浏览器的主要玩家如360,搜狗,金山基本不参与这一阶段的竞争,360只在Android系统提供的WebView组件之上做了一层壳,搜狗和金山压根就没有什么大动作,360去年上半年还通过猎头在挖做手机浏览器内核的人,据说金山本来也准备投入,但是后来都改变了策略,更多把人力投入到桌面浏览器的竞争上面,在手机浏览器上,估计会直接参与第二阶段的竞争(听猎头说,传言金山本来已经成立手机浏览器团队,但是后来又合并回去全力做桌面浏览器)。

    第二阶段的“自有内核”会是基于Chrome&Blink,Chrome从WebKit主干分离出Blink,开始自己独自主导浏览器内核的发展,并且围绕Blink构建了一套Content API,用于将Chrome核心模块如多进程沙盒模型,渲染架构,网络堆栈,V8&Dart虚拟机和Blink内核封装在一起,用于支持Chrome本身和第三方基于Chrome&Blink内核的浏览器的开发(如新版的Opera)。

    从目前的状况来看,Chrome&Blink内核在Android平台大范围普及的时机还不成熟,主要在于Chrome&Blink内核本身还处于一个不太稳定的状态,Content API还在剧烈变化中,代码的性能优化和系统稳定性还有很多不足,并且Chrome本身的多进程架构对手机的性能有比较高的要求,包括CPU/GPU和内存大小,一些性能较差的手机连基本操作的流畅度都无法保证,另外默认的渲染架构强制要求4.0以上的系统版本。这些原因会导致第二阶段的竞争最早也会在明年才开始,开始贴身肉搏式的剧烈争斗预估也要到2015年。

    估计360,搜狗,金山会直接投入第二阶段的竞争,可能现在已经开始筹建团队和进行初期的技术准备。对他们来说,第一阶段已经基本尘埃落定,参与的意义不大,有限的人力还不如早点开始准备第二阶段,并且他们在桌面浏览器上本来就是基于Chrome在开发,所以第二阶段的竞争对他们来说反而在技术储备上会更有利。

    最终,从明年到2015年上半年这段时间,国内Android手机浏览器在“自有内核”上竞争的主要玩家会逐步增加到5~6家,因为各方都是基于Chrome&Blink进行二次开发,要获得相对于其它竞争者的技术优势会变得殊为不易。技术上的领先更多会体现在谁能更快跟进HTML5标准的发展,跟进由Google主导的Chrome&Blink内核本身的演进,一些局部的性能优化和更好地解决设备兼容性问题和系统稳定性问题。
     
  • Roger 1:46 pm on April 3, 2013 固定链接 | 回复  

    [Slides] Why your Android Apps Suck 

    Make it as slides (https://rogeryi.wordpress.com/2013/03/26/why-your-android-apps-suck/) :

     
  • Roger 7:55 pm on March 26, 2013 固定链接 | 回复
    Tags: ,   

    Why your Android Apps Suck 

    Why I wrote this article?

    When I learn more about Android’s graphics system, and do more work about how to use CPU/GPU in more paralleled way to improve the graphics performance in Android, I start to think that there are actually some big design mistakes in Android graphics system, especially the rendering architecture in the client side.

    Some mistakes have been solved after 3.x, especially above 4.1, but others can never be solved due to the compatible reason. As developers, we need to know how the Android graphics system work, how to utilize the new features Android 3.x and 4.x provided, and how to do the optimazation and overcome the shortage of Android.

    Direct Rendering

    In the very beginning, Android’s client/server architecture of its graphics system choose the direct rendering mode, Android team develop a lightweight Window Compositor – SurfaceFlinger by themself, it response to create native windows, allocate graphics buffers and composite the window surface to display (via framebuffer). In client side, apps (through Android runtime) can use CPU to access the graphics buffer of native window directly (through Skia), or use GPU to manipulate it indirectly (through GLES). This direct rendeing mode is more appropriate than the traditional X in desktop Linux.

    Window Composite in Server Side

    SurfaceFlinger use GLES1 to do the window composition (via texture operation) in the very beginning, this cause two issues :

    • GPU may have more efficient way to do the window composition than use GLES;
    • When the client side also use GLES to render the window surface, it may competes with the server about the GPU resources;

    Just mention, when GPU do not support GLES1, Android has a built-in SW version GLES1 stack, and it can use copybit HAL module provided by chip vendor to accelerated the texture operation.

    So, after 3.0, Android introduce hwcomposer HAL module to solve these issues, also abandon the old copybit module. Chip vendor can through the implementation of hwcomposer module to declare they can do all of or part of windows’ composition by themselves, usually with dedicated hardware and always more efficient than use GLES. Also, after 4.1, hwcomposer can provide the vsync signal of the display, so that Android can sync three things together :

    • the windows composition in server side
    • the rendering of window surface in client side
    • the refresh of display

    vsync

    Rendering Architecture in Client Side

    The most mistake Android team make is the rendering architecture of its GUI framework :

    1. It do not has a layer rendering architecture (or called scene graph in some GUI fw);
    2. It do not has a dedicated rendering thread to render the window surface;
    3. It’s rendering only use CPU until 3.0;

    The first one is partially support after 3.0, the third is support after 3.0, but the second problem can never be solved…

    Compare to iOS

    In iOS, every View has a Layer as its backing store, app can create more Layers for better performance. View’s content will be drew into its Layer, as long as the content do not changed, the View do not need to draw itself again. iOS do a lot of things to avoid change the content of a View, many many properties of a View can be changed without affect to its content, such as background, border, opacity, position, transformation, even the geometry!!!

    The composition of Layers done by another dedicated rendering thread, it always use GPU to draw each Layer to the window surface. The main thread only reponse to handle touch event, relayout the Views, draw View’s content into its Layer when necessary, etc… So the main thread only use CPU and the rendering thread use GPU mostly, and I think there will be just a few synchronization between these two threads, and they can run concurrently in most of time.

    But in Android, the main thread need to do everything, such as handle touch events, relayout views, dequeue/enqueue graphics buffer, draw views’ content on window surface, and other things need to be done by app… And it only use CPU before 3.0!!! Even the position of a View just change one pixel, Android need to redraw its content along with the contents of other Views overlapped, and the content drawing is very expensive for CPU!!!

    The Improvements

    A lot improvements have been made after 3.0 to overcome the shortage of previous versions. Android 3.0 introduce a new hwui module, and it can use GPU to accelerated the drawing of View’s content, it create a hw accelerated Canvas to replace the old sw Canvas, the new Canvas use OpenGL ES as its backend instead of use SkCanvas from Skia.

    Android 3.0 also introduce the DisplayList mechanism, DisplayList can be considered as a 2D drawing commands buffer, every View has its own DisplayList , and when its onDraw method called, all drawing commands issue through the input Canvas actually store into its own DisplayList. When every DisplayList are ready, Android will draw all the DisplayLists, it actually turn the 2D drawing commands into GLES commands to use GPU to render the window surface. So the rendering of View Hierarchy actually separated into two steps, generate View’s DisplayList, and then draw the DisplayLists, and the second one use GPU mostly.

    When app invalidate a View, Android need to regenerate its DisplayList, but the overlapped View’s DisplayList can keep untouched.  Also, Android 4.1 introduce DisplayList properties, DisplayList now can has many properties such as opacity, transformation, etc…, and the changed of some properties of View will just cause changed of corresponding properties of its DisplayList and need not to regenerate it. These two improvements can save some times by avoid regenerate DisplayLists unnecessary.

    Although Android can never has a layer rendering architecture, it actually introduce some Layer support after 3.0, a View can has a Layer as its backing store. The so called HW Layer actually back by a FBO, if the content of View is too complicated and unlikely to change in the future, use Layer may help. Also, when a View is animating (but content do not change), cache itself and its parent with Layers may also help. But use Layer with caution, because it increase the memory usage, if your want to use Layers during animation, your may need to release them when the animation is finish, Android 4.2 provide new animation API to help you about that. Also, because Android use GLES to draw the content of View, so most Views’ drawing will be fast enough, and the use of Layer may be unnecessary.

    Android 4.0 also introduce a new type of native window – SurfaceTextureClient (back by a SurfaceTexture) and its Java wrapper TextureView, app can create and own this kind of native window and response to its composition. If the content of View is too complicated and continue to change, TextureView will be very helpful, app can use another thread to generate the content of TextureView and notify the main thread to update, and main thread can use the TextureView as a normal texture and draw it directly on the window of current Activity. (TextureView can also replace the usage of original SurfaceView and GLSurfaceView)

    Android 4.1 make the touch event handling and ui drawing sync with the vsync signal of display, it also use triple buffers to avoid block the main thread too often because it need to wait the SurfaceFlinger to do the page flip and release the previous front buffer, and SurfaceFlinger will always sync with vsync signal of display.

    The OpenGL Renderer for hw accelerated Canvas is continue be improved and become faster, especially for complicated shape drawing.

    But…

    But Android can never has a dedicated rendering thread… Although the drawing is much faster than before, and keep the changed of everything as little as possible during animating, it still need to share the 16ms interval with other jobs in main thread to achieve 60 fps.

    So…

    So, as developer, we need to utilize the improvements in higher version Android as much as possible :

    1. Turn on the GPU acceleration switch above Android 3.0;
    2. Use the new Animation Framework for your animation;
    3. Use Layer and TextureView when necessary;
    4. etc…

    And avoid to block the main thread as much as possible, that means :

    1. If your handle the touch events too long, do it in another thread;
    2. If your need to load a file from sdcard or read data from database, do it in another thread;
    3. If your need to decode a bitmap, do it in another thread;
    4. If your View’s content is too complicated, use Layer, if it continue to change, use TextureView and generate its content in another thread;
    5. Even your can use another standalone window (such as SurfaceView) as a overlay and render it in another thread;
    6. etc…

    Golden Rules for Butter Graphics

    • Whatever you can do in another thread, then do it in another thread;
    • Whatever you must do in main thread, then do it fast;
    • Always profiling, it is your most dear friend;

    All you need to do is keep the loop of main thread under 16ms interval, and every frame will be perfect!

    The Last Word

    When I finish this article, what make me think most is, when you make a big design mistake in the very beginning, and you can not change it due to some reasons, no matter how hard you try to patch it in future, it will never get perfect again.

    Android team make huge effects to provide features like Strict Mode, AsyncTask, Concurrent & Background GC, hw accelerated Canvas, hw Layer, TextureView, vsync, triple buffers, etc… All they do just about two things, do everything you can in another thread, and make the must thing in main thread faster, and these actually help a lot. But no matter how hard you try to use these features to improve your app, it is nearly impossible to get every frame perfect, because it is so hard to forecast everything the main thread will do in every loop, it may suddenly jump into something totally uncontrollable by you app and make you break the 16ms curse.

    And the worse is, if you has a good design, you can continue improve it (like utilize more advance hardware), but the developer need not to know anything about this and do not need to change even one line of their code, if the app run on higher version OS with faster device, it just got the performance boost. If you has a bad design, although you do a lot of things to patch it, but the developer need to know why, they need to rewrite their code to use these new features, they need to know how to avoid the trap, they need to know how to make compatible with older version system, and many many other things…

    This is too hard for a developer just want to build a useful and beauty app…

     
    • fluke 3:03 下午 on 四月 3, 2013 固定链接 | 回复

      Good job. It’s really a good article that tells a lot truths about Android’s UI framework.

      I quite agree that Android’s laggy is caused by rendering UI in the same thread (main thread). In iOS there is a dedicated thread in real-time priority for rendering the UI.

      I think there are two more reason for Android is laggier then iOS:
      1. GC. though not very often and can be avoid in some displaying loop.
      2. apple’s custom chip.

      Do the right design at the beginning is so important.

      • Roger 3:23 下午 on 四月 3, 2013 固定链接 | 回复

        The first reason is true before background & concurrent GC appear, after 2.3, GC can happen in another thread in background.
        The second is always true, but I think the gap become more and more smaller, because every major Soc vendor begin to design their Soc optimized for Android in the very beginning.

    • Dilbert 9:12 下午 on 四月 11, 2013 固定链接 | 回复

      Compare to iOS : The composition of Layers done by another dedicated rendering thread, it always use GPU to draw each Layer to the window surface.
      The main thread also reponse to draw View’s content into its Layer when necessary, etc…

      on Android :
      The window surfaces are composited to screen by a separate system service (in a separate thread called surfaceflinger, use gpu) . this is very much like what iOS is doing with its views being composited by a separate thread

      so i dont know what is the difference ,
      and the second problem : android do not has a dedicated rendering thread to render the window surface?

      • Roger 4:08 下午 on 四月 12, 2013 固定链接 | 回复

        Layer composition and Window composition are different, the first happen in your app’s process, it composite the layers into your app’s current window’s back buffer, and then it will need to ask the server to do the Window composition, server need to do the page flip, swap the updated window’s back/front buffer, and then copy each visible window’s front buffer to framebuffer of os, this usually happen in another process.

    • 匿名 5:22 下午 on 一月 8, 2014 固定链接 | 回复

      Why can’t skia use its OpenGL
      backend directly but hwui?

  • Roger 11:47 am on March 25, 2013 固定链接 | 回复
    Tags: , ,   

    Introduce My Work 2 

    早前写了一篇文章“Introduce My Work”,用一个例子 —— HTML5 Canvas的一个简单实现,介绍自己工作的内容,而这篇文章试图去描绘自己工作内容所需的一个完整的知识体系的层次结构(见下图),并对其进行简单介绍。

    android_graphics

    Browser App

    基于系统的GUI框架开发完整的浏览器应用。

    Android GUI Framework

    1. 了解Android的View System机制;
    2. 从3.0开始Android支持使用Layer作为View的Backing Store,用于对动画进行加速;
    3. 了解Android Window Surface相关的Java封装和实现细节;
    4. Canvas是Android Java层用于2D绘图的主要对象;

    WebKit

    WebKit通常可以分为WebCore和WebKit Port,在WebCore中,跟渲染相关的对象主要有RenderLayer, RenderObject, GraphicsContext, Image, ImageBuffer等,而WebKit Port则负责整个渲染架构的设计和实现,它需要考虑:

    1. 使用什么作为Backing Store,是Vector(矢量图),还是Bitmap(位图),还是Texture(贴图),还是Surface(Window Surface);
    2. 支不支持Layer Rendering(分层渲染,需要WebCore开启Accelerated Compositing的支持),支不支持Tile Rendering(分块渲染);
    3. 采用多线程(单进程)的渲染架构还是像WebKit2或者Chrome那样的多进程渲染架构;

    Android Graphics Stack (Client)

    Android在客户端的绘图堆栈通常包括:

    1. Skia,一个使用CPU进行2D绘图的绘图库;
    2. OpenGL ES,使用GPU进行3D和2D的绘图的API(比如Android 3.0后出现的hwui模块就使用GLES来取代Skia用于2D绘图,实现GPU加速的2D绘图);
    3. EGL,衔接GLES和系统的Native Window系统的适配层;
    4. Surface(Native Window),可以通过Surface接口的一个Stub实现操控远程的Native Window,另外Android 4.0后,应用还可以创建自己的Native Window并且自己负责它的混合;

    Android Graphics Stack(Server)

    SurfaceFlinger是Android用于管理Display和负责Window Composite(窗口混合),把应用的显示窗口输出到Display的系统服务。

    Android Drivers(HAL)

    Android的驱动层,通过Android本身的HAL(硬件抽象层)机制,运行于User Space,跟渲染相关的包括:

    1. hwcomposer,如果硬件支持,SurfaceFlinger可以请求hwcomposer去做窗口混合而不需要自己来做,这样的效率也会更高,减少对GPU资源的占用;
    2. gralloc,用来管理Graphics Buffer的分配和管理系统的framebuffer;
    3. copybit,早期Android在GPU不支持完整的GL ES1的情况下,内部的软件版本的GL ES1实现可以使用copybit来加速贴图操作(其实也就是加速窗口混合),hwcomposer出现后就已经移除了;
    4. gles/egl驱动;

    Linux Kernel and Drivers

    除了标准的Linux内核和驱动(如fb是framebuffer驱动),硬件厂商自己的驱动外,Android自己的一些Patches:

    1. ashmem,异步共享内存,用于在进程间共享一块内存区域,并允许系统在资源紧张时回收不加锁的内存块;
    2. pmem,用于分配物理地址连续的内存块,一般从已经预留的内存区域中分配,主要用来作为Graphics Buffer,不过4.0以后,逐步被更完整的内存管理器ION替代;
    3. binder,高效的进程间通信机制;
    4. sync,用来将呼叫者阻塞,并强制跟显示器的刷新保持同步;

    Hardware

    CPU,GPU,VPU(Video Process Unit),和内存等等。

     

    虽然目前的工作主要集中在WebKit这一层,但是由上至下打通每一个层次,对更好的拓展自己的工作范围,具备挑战更高难度的任务的能力,产出更高品质的成果,的的确确是非常重要的。应该说,自己目前仅仅只是把上面的一个知识体系的架子搭起来,描绘出一个较为完整的轮廓而已,很多部分也仅仅是了解一些简单的概念,特别是底层的层次,无论是其中的原理还是实现的细节了解的非常少。而未来的两到三年的时间,要做的最重要的事情就是不断的拓展,补充和完善上述的知识体系,以期能够早日达成“恢恢乎其于游刃必有余地矣”的境界。

     
  • Roger 11:11 am on February 2, 2013 固定链接 | 回复
    Tags: , ,   

    我的2012 

    去年放假时为我的2011一整年写了一篇回顾,今年也打算继续,希望以后每年坚持下来形成习惯。

    2012年的最大变化就是工作内容从外壳的GUI框架层转向内核的网页渲染:
    • 年初第一季度的研究重点是在Android 4.0系统浏览器的硬件加速AC渲染架构和整个适配层的架构;
    • 接下第二季度的工作是参考系统浏览器的渲染架构,在我们的浏览器上也实现多线程渲染架构,当时考虑4.0的渲染架构太过复杂,而且很多版本兼容性问题无法很好解决,所以还是以2.3的系统浏览器为主要参考对象;
    • 完成初始的预研工作,实现演示Demo后,项目这边决定第三季度在8.6上多线程渲染架构改造,不过后续的实际开发工作中碰到了很多困难,主要是因为程序从原来的单线程架构一下子改成多线程,需要重写的模块和修改的地方非常多,一些原来没有很好处理多线程的地方引发了大量的崩溃问题,并且多线程在低端机上的性能表现一开始不是很好,也花费了大量的时间去做性能分析跟优化;
    • 接下来的8.7版本我的主要工作是在8.6的基础上进一步优化一些基础渲染性能,如滑屏,缩放等,最终的表现也还算不错,渲染性能比起以前的版本改进很大,虽然还无法跟支持硬件加速的4.x系统浏览器相比,但是在还未支持硬件加速的情况下也基本上做到极致了;
    • 做完8.7后,8月下旬开始准备我们浏览器整个适配层的改造工作,在8.6,8.7多线程渲染架构改造的基础上,我们决定完全抛弃掉以前自己写的C++适配层和一套从塞班时代延续过来的自己开发的C++ GUI Toolkit,完全转向跟系统浏览器一样的Java和C++结合的适配层架构,跟Android SDK一样,内核为外壳提供一个标准的Android UI组件WebView,而外壳完全使用Android原生的UI组件进行开发。不过跟8.6,8.7时不太一样的地方在于,这次我主要负责前期技术研究和框架搭建的工作,在完成Demo,技术文档和培训与宣讲后,后续的主要工作就是协助其它同学对各自负责的模块进行设计与实现,只负责一些设计和代码Review的工作而不再直接参与8.8的项目工作;
    • 10月开始了硬件加速方面的研究,在之前工作的基础上,开始移植4.1系统浏览器的渲染架构代码(这时4.1已经发布了,并且4.1比起4.0又复杂了很多),初始的移植工作完成后,已经可以运行一个硬件加速AC的Demo,接下来的主要工作就是解决版本兼容性问题,我们不但需要解决2.x和4.x之间的版本兼容性问题,而且还要解决4.x不同版本之间的兼容性问题,版本兼容性问题的解决使得我们可以一个程序同时运行在2.x和4.x上面,支持非硬件加速和硬件加速两种不同的渲染路径,可以在运行时根据系统决定选择哪种渲染方式,最后因为4.2的发布,我们又把4.2的代码也同步了过来;
    • 前面的工作完成后就差不多到年底了,马不停蹄地又开始了硬件加速2D Canvas的研究,为此也学习了Android的OpenGL ES编程,加深对Android Native Window System,EGL,GLES的理解,另外还研究了Chrome for Android的2D Canvas实现,到目前为止,硬件加速2D Canvas已经基本实现,Demo初始的测试结果还不错,跑GUIMark 3的帧数比Chrome正式版(Chrome 18)要高,不过比Chrome Beta版(Chrome 25)要低,但是考虑到目前我们所使用的Skia的代码比较旧(来自Android 4.2 AOSP),而Chrome这几个版本还在不断优化Skia的性能,后续升级Skia后,相信性能还会再有所提高;
    2013年,最重要的工作就是在之前的硬件加速相关的研究工作的基础上,协助硬件加速AC,硬件加速2D Canvas顺利进入产品,从过往的经验也可以知道,从Demo到产品,后续要做的工作还很多。另外下半年也有可能会去研究WebGL(3D Canvas)。

    而对自己的职业发展的规划,主要的技术研究方向还是会集中在以下几个领域:
    1. 网页渲染相关的研究(CSS动画,Filter/Shader,2D/3D Canvas,Chrome的多进程渲染架构等等);
    2. Android图形子系统
    3. 2D/3D绘图(Skia,OpenGL ES等等);
     
  • Roger 10:32 am on January 18, 2013 固定链接 | 回复
    Tags: Accelerated 2D Canvas, Accelerated Compositing, , ,   

    Introduce My Work 

    图像

    我在LinkedIn上面的个人简介是:

    Roger at UC Mobile Ltd. (www.uc.cn), focus on graphics stack (rendering architecture) research of WebKit based Browser in Android platform, include the graphics stack of WebKit itself along with the display subsystem of Android platform, and design how to combine the best of both them to achieve butter graphics performance of page rendering.

    简单的说就是专注于Android平台基于WebKit的浏览器绘图堆栈的研究,可是,到底什么是所谓的”Android平台基于WebKit的浏览器绘图堆栈“,下面我用一个例子来说明。

    我们来考究一个最简单的HTML5 Canvas在Android平台基于WebKit的浏览器上的实现:

    1. 如果网页包含Canvas标签,或者由JavaScript动态生成,都会导致WebKit内核生成一个HTMLCanvasElement Node对象;
    2. 当JS从Canvas元素获得一个2D Context对象时(var ctx = canvas.getContext(“2d”)),实际上这个Context JS对象会跟一个C++的CanvasRenderingContext2D对象绑定,JS在这个Context上的全部调用都会被虚拟机转发给对应的CanvasRenderingContext2D对象;
    3. WebKit内部的2D绘图是基于GraphicsContext的,所以CanvasRenderingContext2D对象需要一个GraphicsContext来执行真正的2D绘图操作,它会向HTMLCanvasElement对象发出请求,通过它的drawingContext()方法返回一个GraphicsContext;
    4. 而HTMLCanvasElement则把这个请求转发给内部的ImageBuffer对象,所以真正用于绘图的GraphicsContext是由ImageBuffer提供的;
    5. ImageBuffer顾名思义,是用来管理一块位图缓存,默认情况下,它会分配一块内存,把这块内存封装成一个位图(在Android平台是SkBitmap),然后通过这个位图创建一个平台相关的绘图上下文PlatformGraphicsContext(在Android平台是SkCanvas和PlatformGraphicsContextSkia),最后把这个PlatformGraphicsContext封装成一个平台无关的GraphicsContext返回;
    6. 从上面可知,当JS通过Canvas元素获得的Context对象绘图时,最终是绘制到HTMLCanvasElement对象内部的ImageBuffer对象管理的一块内存里面;
    上面仅仅说明了JS调用本身的绘制路径,要最终在屏幕上看到结果,我们还需要把ImageBuffer里面的内容绘制到窗口上:

    1. 当JS执行Context对象的每一个绘图操作时,对应的HTMLCanvasElement对象都会对外广播一个内容发生变化的通知(canvasChanged);
    2. 这个通知会被转换成网页内容的某个区域的重绘请求;
    3. 这个网页内容的重绘请求会被WebKit内核的适配层拦截,在Android平台上,它最终会被转换成用于显示这个网页的View对象的某个区域的重绘请求(View.invalidate),重绘区域需要经过从网页的内容坐标系到View的显示坐标系的坐标转换;
    4. 当Android当前Activity的View Hierachy的某个View需要重绘时,Android会在稍后的某个一个时间点发起一个View Hierachy的遍历操作(ViewRootImpl.doTraversal);
    5. 在这个View Hierachy的遍历操作中,Android会生成一个Canvas对象,然后逐个调用View的onDraw方法,让View把自身的内容通过这个Canvas绘制到当前的窗口上,这个Canvas对象实际上从当前窗口对应的Surface对象中获得,而Surface对象需要从当前窗口的Graphics Buffer队列中取出一块空闲的Buffer(这个Buffer由系统的窗口混合器SurfaceFlinger分配),然后把这块Buffer封装成一个SkBitmap,再根据SkBitmap生成SkCanvas,再根据SkCanvas生成Java Canvas…
    6. 当用于显示网页的View对象的onDraw方法被Android系统调用到时,它需要重新把C++的SkCanvas对象从Java的Canvas对象中取出来,然后把这个SkCanvas包装成WebKit所需的GraphicsContext对象,传给WebKit让它去绘制网页,当WebKit绘制到对应这个Canvas元素的Render Object(RenderHTMLCanvas)时,RenderHTMLCanvas实际上会把这个绘制请求转发给它对应的HTMLCanvasElement对象(就是前面说的那一个),而HTMLCanvasElement则把自己的ImageBuffer对象通过传入的GraphicsContext最终绘制到当前窗口上;
    7. 当Android遍历完整个View Hierachy,所有View都通过传入的Canvas绘制到了当前的窗口上,但这时我们还未能在屏幕上看到更新的内容,因为实际上我们是绘制到了当前窗口的back buffer,Android还需要把绘制完的back buffer解锁,放回窗口的Graphics Buffer队列,通知SurfaceFlinger窗口的内容发生了变化(Surface.unlockAndPost);
    8. 当SurfaceFlinger收到窗口更新的通知时,它会切换窗口的前后台缓存(Page Flip),然后逐个把当前可见的窗口的front buffer拷贝到系统的framebuffer里面去,这样我们最终才在屏幕上看到Canvas绘制的结果(Android 4.0开始,如果硬件支持,可以省略掉将窗口front buffer拷贝到系统framebuffer这一步,由display hardware自己负责);
    上面的例子足够复杂吗,实际上已经省略了很多不太重要的部分,也简化了一些比较复杂的概念比如Android的Native Window和Window Compositing机制,并且这仅仅是一个最最最简单的实现!!!

    如果我们需要考虑支持:
    1. 支持像系统浏览器一样的多线程渲染架构或者像Chrome一样的多进程渲染架构;
    2. 支持Android的GPU加速绘图(从Android3.0 开始支持);
    3. 支持WebKit的图层混合加速(Accelerated Compositing);
    4. 支持硬件加速的2D Canvas实现(Accelerated 2D Canvas);
    上面的每一个选项都会让本来的流程再加倍的复杂,而这些就是我的主要工作内容 ^_^
     
    • unbug 10:38 上午 on 一月 18, 2013 固定链接 | 回复

      强文,营养丰富,收藏备读!

    • 一丝 10:55 上午 on 一月 18, 2013 固定链接 | 回复

      虽不明,但觉厉(PS,楼上的你好讨厌捏,老是抢在我前面。)

  • Roger 6:47 pm on January 3, 2013 固定链接 | 回复  

    Ubuntu for Phone 

    phone-photo-hero

     

    新年伊始最大的IT新闻莫过于Ubuntu for Phone的发布,系统的亮点除了全手势操作外,最让人感兴趣的就是插上底座后可以转换成桌面模式,作为一台thin PC来用,官方宣传语是Introducing the superphone that’s also a full PC。(其实自己一直期望Android和Chrome OS能够在底层进行融合,两者可以共存并且共享数据,分别运用于移动模式和桌面模式)

     

    目前已知的信息不多,只是知道除了像Tizen一样,WebApp会得到一等公民的待遇,获得系统级的支持外,跟Sailfish一样,可以使用QML/Qt开发原生应用,对于游戏来说也可以直接使用OpenGL。

     

    虽然很高兴看到Qt得到支持,但是官方暗示系统底层模式是C++编写,QML应用是native应用,效率会比Android的Java来的好就有点误导群众了,应用和系统是否流畅跟开发语言的关系不大,基本取决于系统的绘图堆栈,而无论是Android还是QML,背后的绘图堆栈都是C++编写的,跟上层应用的开发语言没有半毛钱关系,Android发展到现在,绘图堆栈已经改进了很多,可以更充分的利用硬件性能,而不像早期过多依赖于CPU进行计算,当然QML背后的渲染引擎从目前已知的资料来看也相当优秀。另外QML本身也是一种脚本语言,运行在v8 JavaScript虚拟机上,相对而言Java还更原生一些。

     

    Ubuntu为了争取硬件厂商的支持,号称完全兼容Android的硬件驱动(官方的宣传语是If you already make handsets that run Android, the work needed to adopt Ubuntu will be trivial),只是不知道会使用Android的系统模块,还是会使用标准的Linux系统模块来取代Android,比如窗口混合器是使用Android的SurfaceFlinger还是使用Wayland就不得而知了。
     
    • fxwan 11:44 上午 on 一月 13, 2013 固定链接 | 回复

      http://andreasgal.com/2013/01/08/why-the-web-is-going-to-win-mobile/
      博主可以参考这篇文章的comments部分,V8某些方面比Dalvik优秀可能并不为过。

      • Roger 6:32 下午 on 一月 13, 2013 固定链接 | 回复

        这个虽然有可能,不过文章中我强调的是系统和应用是否流畅,跟应用开发的语言本身关系并不大,主要取决于系统本身,特别是图形子系统。

    • fxwan 7:34 下午 on 一月 13, 2013 固定链接 | 回复

      嗯,这点没问题。Skia看上去更现代(?)

      • Roger 7:54 下午 on 一月 13, 2013 固定链接 | 回复

        现在的Android,使用Skia的地方已经不多了,无论是服务端的窗口混合器,这个从一开始就是使用OpenGL ES1,应用端UI控件的绘制,现在也改成使用OpenGL ES2。

  • Roger 11:05 am on December 11, 2012 固定链接 | 回复  

    如何编译Chrome for Android 

    Screenshot_2012-12-11-10-21-43

     

     

     

    编译Chrome for Android目前有两种方式,一是在ROM编译环境下编出libchromeview.so,二是用Chromium主干的代码编译出ContentShell(一个测试用的外壳,只包含核心的代码,不包含Chrome的扩展特性,说明参见http://www.chromium.org/developers/content-module),这两种方式目前都只支持在64位Ubuntu下面进行。


    在ROM编译环境下编出libchromeview.so
    这种方式比较简单,下载当前版本Chrome for Android的tarball(http://chromium-browser-source.commondatastorage.googleapis.com/chrome_android_tarball.html),解压后把Chrome目录放入ROM目录的$ROM/external下面,然后按照README.Chrome_for_Android_SourceDistribution里面的说明进行编译即可。
    1. 编译出来的libchromeview.so,可以按照README.Chrome_for_Android_SourceDistribution说明打一个新的Chrome.apk运行,也可以直接替换掉手机里面/data/data/com.android.chrome/下面的libchromeview.so运行;
    2. 不知道是不是版本不匹配的关系,用最新的Chrome搭配自己编译的libchromeview.so,复杂的网页会崩溃,简单的网页就还OK;
    3. 可以输出日志(#include “/base/logging.h”),但是没法调试和跟踪(理论上应该可以使用命令行gdb进行调试,不过配置起来应该比较麻烦,没有去尝试);

    用Chromium主干的代码编译出ContentShell
    这种方式比较麻烦,具体步骤请参考(https://code.google.com/p/chromium/wiki/AndroidBuildInstructions)。
    1. 下载Chromium的tarball(http://chromium-browser-source.commondatastorage.googleapis.com/chromium_tarball.html)后需要使用gclient sync -nohooks同步新的代码,tarball里面的svn记录是1.6版本的,如果你的svn是1.7版本,需要先downgrade到1.6版本;
    2. 同步最新代码的时候,如果提示guava和jsr-305这两个目录同步错误,需要先移除$SRC/third_party/guava和$SRC/third_party/jsr-305后再重新同步(后续新的tarball应该不需要了);
    3. gclient runhooks一直失败,不过貌似也不影响编译;
    4. 如果编译时提示缺少$SRC/build/util/LASTCHANGE文件,可以从上面的Chrome for Android的tarball里面copy过来;
    5. 运行build/android/adb_gdb_content_shell就可以使用gdb进行调试;
    6. adb_gdb_content_shell实际上调用了adb_gdb,adb_gdb在中文Ubuntu环境下有一个bug,第861行”if [ “$STATE” != “Running” ]; then“可能会失败,因为在中文环境STATE实际值可能是”运行中“,这一行需要改成”if [ “$STATE” != “运行中” ]; then“;
    7. 如果提示权限不够,可以把849,859这两行改成”(“$ADB” shell su -c “$TARGET_GDBSERVER :$TARGET_PORT \
      –attach $PID” > $GDBSERVER_LOG 2>&1) &“,不过需要已Root的设备和开启ADB的Root权限;
     
c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
回复
e
编辑
o
Show/Hide comments
t
返回顶部
l
Go to login
h
Show/Hide help
shift + esc
取消