webview同步合成

来源:互联网 发布:数据分析专业就业前景 编辑:程序博客网 时间:2024/05/29 12:31
问题
Chrome合成器现在已经有了软件模式,但是只靠这一点还不能解决现有AndroidWebview的使用/滥用问题。
目前AndroidWebview系统的渲染情况如下:
● Nonmodal(非模态)
用户无法通过WebView API指定WebView是处于软件模式还是硬件模式。相反地,canvas是一层接一层的传递给draw调用的,而这个canvas的后端存储可以是硬的也可以是软的。尽管如此,只有在WebView连接到一颗硬件加速的View Tree时,硬件绘制才会发生,而软件绘制到一块side canvas上则随时都可以发生。
同步
绘制命令必须阻塞,直到一帧渲染(canvas)完。
及时(justin time
在绘制命令到达之前,滑动偏移和缩放因子(也可能通过矩阵起作用)可能已经变化了几次。WebView也可能初始化的比屏幕大,每一帧只绘制当前裁剪区域。
软件模式下不会丢失内容
如果是绘制到软件canvas上,不会由丢失或者模糊的tile.
(但如果是硬件作为后端存储的canvas,checkerboardis ok.)
关于上述特性,有两个代表性的使用场景:
基于WebView的第三方浏览器,使用了一个onscreenhardware canvas,允许用户来回滑动。现在它想取整个文档的一个缩略图。
为了做这件事,它会创建一个小的softwarecanvas,并将一个0.1缩放因子的矩阵应用到该canvas上,然后调用webView.draw(softwareCanvas).(
这个函数是取缩略图的推荐用法,代替已经半过时的capturePicture)
一个应用使用underlying文档的大小初始化webview,高度是viewport20倍。然后在完全忽略scrolloffset的情况下,使用一个矩阵移动这个webview.这个过程中应该做到没有任何的过度绘制或者其他的性能影响。
Chromium webview需要努力精确重现AndroidWebView的这些特性,而不是只做到大致相似或者绕开它。否则向后兼容问题会很难解决。幸好,impl-sidepainting开启了精确重现AndroidWebView这些特性的实现方式。
解决大纲(更新)
下面是为为提出来的完成上述需求的一个最简单的计划,依赖impl-sidepainting.
首先,我们可以利用WebView单进程的优势,将renderer compositor impl threadbrowserui thread合并。
这样可以使我们的线程模型与Android Browser线程模型(包含一个UI线程,一个WebKit线程,一个raster线程)更匹配。
我们的WebKit线程只和某个message loop对话,而不关心这个message loop是一个新建的线程还是封装的一个已有线程。
手势事件流:
1.一个手势来自与Android Java Code.
2.当需要发送IPC时,作为替换,我们发送到一个新的类SyncInputEventFilter.这个类会直接调用CC。有三种情况:
 a. 如果event hit root layer,CC拒绝这个event,并让WebView-specific code 处理 scrolling.
 b. 如果event hit sublayer,CC吸收这个event,并scroll sublayer.
 c. 如果event hit slow-scroll区域,CC使用HandleOnMainThread拒绝这个event,SyncInputEventFilter发送IPCrender进程。
WebView被要求绘制时:
1.WebView.onDraw()中,留意当前的transform,scale,clip rect,最新的android矩阵都要考虑在内。
2.1中的信息设置LayerTreeHostImpl的状态。
3.通过“BeginMainFrame”/"deadline"调用CC马上开始绘制。
4.计算layer的绘制属性,在CaclDrawProperties中给rootlayer添加额外的transform,clip rect.
5.以下是派生的方法:
如果是softwarecanvas(OutputSurface::ForcedSoftwareDraw()标识)
 i.遍历layer tree只生产resource-free DrawQuads.
 ii.为当前帧创建一个本地的SoftwareRenderer,PictureDrawQuads光栅化到software canvas上。
如果是hardwarecanvas:像平常一样产生GL命令,并推送到command buffer中。
6.WebView.onDraw()返回。
7.如果是硬件绘制,绘制函数将被调用,不改变线程的情况下,在system context下,使commandbuffer立即执行整个GL流,执行完再清除GL state保证整个system context不变。
下面是此方法的一些实现:
● “Normal”软件合成只被部分使用一个临时的cc::SoftwareRenderer实例完成“tile free software compositing”模式。
我们没有browser compositor.
● renderer compositor不会自发调度frames.直到被drawfunctor调用,它才会开始绘制。
由于软件绘制不需要使用tiles,我们延迟到第一次收到硬件绘制命令时才创建Tiles.
所以没有attach到硬件加速的view时,TileManagermemory-limit应该是0.
软件绘制命令存在如下的性能权衡:
  ○ scrolling/pinchingtiled compositing要慢,因为SkPicture的性能具有不确定性。
新的失效区域绘制到最终canvas上的过程比tiled compositing要快,因为两者之间没有Tile.
鉴于软件绘制的Webview通常用在取缩略图/截图这类应用,这种权衡还是合理的。注意AndroidWebview的软件绘制路径也是直接从SkPicture raster的,所以滑动体验不会衰退。
不允许在draw functor以外触发任何GL调用,因为我们没有权限在draw functor以外使用这个context.
尽管如此,我们可在任何时候使用为GL Tile创建和使用gralloc()Buffer
对于capturePicture和通常的软件绘制,我们可以重用同样的软件绘制路径,因为SkPicture同样可以是绘制目标。
如果我们对canvas应用clip和矩阵,SkiaR tree优化需要做正确的事情。
Render Surfaces and alpha
对于硬件绘制,render surfacesalpha混合可以正常工作.但是对于软件绘制,问题来了,
可能发生绘制到viewtree attachment外面的情况。这些情况下,如果我们创建一个render-surface资源并持有它,
我们可能永远都接收不到下一个绘制调用了,而且当需要销毁这个rendersurface时,我们也没有明显的时间。
● CC中进行的不同层的alpha混合,通常需要依赖Tile作为Buffer存在才能正确进行,但是我们没有Tile.
在这些场景中,我们可以创建一个per-frame single-shot rendersurface,或者忽略web平台规范,drawincrorrectly.由于传统WebView也忽略了平台规范,第一个版本我们也采用后一种方式。
 a.在高级的render-surface-based features的场景中,比如clipped 3d transformed layerscss   filters,简单忽略他们是ok的,因为现存的webview类应用都不能使用他们。
 b.对与alpha我们需要在某种形式下提供支持。当前代码hacks SkPicture,在绘制的时候直接绘制到rootlayer.由于alpha混合不是可交换的,导致层比较复杂时,颜色值不正确,但在简单场景下效果还ok.
对硬件渲染模式的改进
只有当WebView第一次连接到硬件加速的Android view上时,才可以使用GL Context.
在此之前,只能接收软件绘制命令。所以,我们必须在只有软件渲染模式的基准上初始化CC,并准备好突然升级到完全的GL渲染。
(需要注意,即使在转变为硬件渲染后,我们仍然需要随时支持软件绘制,---所以,完全的GL模式是软件模式的严格意义上的超类)。
当我们从硬件加速的view上分离,我们需要释放所有的GL资源,并降回到软件模式的基准。
WebView连接到硬件加速的Android View树时,在UI/Compositor线程开始第一次绘制调用前,会有一个同步调用初始化CCGL状态。硬件
初始化必须是同步的,不能等待主线程。
就资源分配而言,传统的Android WebView分配GL Tiles,但是从不分配Software Tiles.如上所述,我们想保留这种方式。所以,在纯软件渲染模式下,
我们将避免Tile分配,在初始化硬件阶段,创建TileManager,并开始光栅化任务。
同样的,如果一个在软件模式基准中不能显示的Layer,比如VideoLayer,GL初始化之前就被attach了,我们也需要保证其正常显示。
重新创建output-surface的路径起初是为了lost-context的恢复设计的,在硬件渲染的升级和降级中,这条路径也为我们做了大部分工作。
问题列表:
不能调用LayerTreeHost::DeleteContentsTexturesOnImplThread,因为PrioritizedResourceManager的清除需要阻塞主线程。
*注意,在Android系统渲染过程中,我们不会使用PrioritizedResourceManager。所以可以简单使用if()摒除这部分代码。
在主线程不能更新新的capabilities/setttings.
 *List:allow_partial_texture_updates,MaxPartialTextureUpdates, using_accelerated_painting
*计划是:在初始化软件模式时,将setting设置正确,但直到硬件初始化完,才开始使用这些设置.
不管是否使用offscreencontext,硬件初始化时都会设置offscreen context.
 *只在需要使用时,设置offscreen context,这需要将决定从主线程中移除。
impltree中是否需要清除资源
 *软件模式不需要分配资源,所以不清除资源也fine.但是需要确保this is the case with test/DCHECKS.
 *或者,调用clean up,并且保证所有的Layer都清除了他们的资源,没有资源泄漏情况;
替换策略
下面的一些想法同样可以提供令人满意的同步行为,但是在性能或复杂度方面遇到了困难。
保持线程分离,在绘制时做同步IPC(这篇文档之前版本的选择方案)。Draw是我们考虑同步的主要位置。在绘制时我们可以在renderercompositor impl线程阻塞BrowserUI线程,从而获得同步行为。
问题:A)由于GL必须在BrowserUI线程中执行,这将导致对delegatedrendering的依赖,这将使架构更复杂。
BAPPS也期望能够同步设置scrollposition,这一点我们无法做到精确的向后兼容。更通常的,Apps可能还会做出很多奇怪的同步假设,但这些假设在这种线程模型下是无法支持的。
● WebKit主线程上阻塞。如果在WebKit主线程做所有的软件绘制,我们的行为就是兼容的。对缩略图类的应用和scrolling-styles应用的软件合成使用WebKit-thread阻塞是很有吸引力的。
问题:A)我们也阻塞了embedderUI线程,把它暴露给高一层的jank,这在老的WebView中是不会出现的。即使在取缩略图的场景中,jankingthe embedder 500ms也是不可接受的。
B)没有明显的证据表明使用软件绘制在性能或准确性上更好。
使用tiles做软件合成。
在软件模式下,代替直接从SKPictures绘制,我们可以在最近的scrollscale值下,发送tile绘制任务到光栅化线程。阻塞直到光栅化完成,然后在使用SoftwareRenderer绘制。这要求LayerTreeHostImpl同时持有SoftwareRendererGLRenderer.由于我们的Tile是由grallocs分配的这一优势,所以可以被软件渲染和硬件渲染使用。
问题:事实证明,读回gralloc非常不容易。在CC中同时管理两种类型的Buffer会比较复杂,而且很难避免内存过度使用。
0 0
原创粉丝点击