首页 > Sketchup > sketchup渲染器在哪里打开-Sketchup Master的内置渲染在哪里?
2023
07-30

sketchup渲染器在哪里打开-Sketchup Master的内置渲染在哪里?

上一篇文章回顾:《淘宝小部件:新开卡技术!》、《2021年双十一淘宝小部件规模化应用》

本文主要从技术角度讲解Widget下Canvas的渲染原理。

在进入正文之前,我们需要先解释一下什么是【小部件】。 小程序是淘宝模块/卡片级开放解决方案,主要为私域小程序提供标准一致的制作、开放和运营能力。 拥有产品卡、权益卡、互动卡等多种业务形态。ISV开发的小部件可以以极低的成本部署到商店、详情、订阅等业务场景,极大地提升了业务的可操作性。提高运营和分销效率。

从终端技术的角度来看,Widget首先是一个业务容器,其特点是DSL标准化、跨平台渲染、跨场景流通:

DSL标准化意味着widget完全兼容小程序的DSL(不仅是DSL,还包括原子API能力、生产环节等),开发者无需额外学习即可快速上手; 跨平台渲染,顾名思义,widget内核(基于weex2.0)通过类似flutter自绘的解决方案,可以在Android、iOS等不同操作系统上渲染完全一致的效果,开发者不需要关心兼容性问题; 最后,跨场景流通意味着Widget容器可以“嵌入到各种技术栈的其他业务容器中,例如Native、WebView、小程序等,从而屏蔽开发者底层容器差异的影响,达到合一的效果”开发和多种运营。

无独有偶,Widget下Canvas的技术方案与Widget容器嵌入其他业务容器的技术方案有很多相似之处,所以下面笔者就讲一下Canvas的渲染。

原理揭晓

端到端整体技术架构

widget技术侧的整体结构如下图所示,从宏观上可以分为“外壳”和“核心”两层。

“Shell”是widget容器,主要包括DSL、widget JSFramework、atomic API以及Canvas等扩展模块。

“Core”是widget的核心,基于新的weex2.0。 在weex1.0中,我们使用了类似RN的原生渲染方案,而weex2.0已经升级为类似Flutter的自绘渲染方案,因此weex2.0承担了widget JS执行、渲染、事件等核心职责。 ,又细分为三个模块:JS脚本引擎、Framework和渲染引擎。 JS引擎在Android端使用轻量级的QuickJS,在iOS端使用JavaScriptCore,并支持通过JSI编写与脚本引擎无关的Bindings; Framework层提供与浏览器一致的CSSOM和DOM能力,此外还有C++ MVVM框架和一些WebAPI等(Console、setTimeout、…); 最后是内部称为Unicorn的渲染引擎,主要提供布局、绘图、合成、光栅化等渲染相关的能力。 Framework和渲染引擎层均采用C++开发,并对平台进行了相关抽象,以更好地支持跨平台。

值得一提的是,unicorn渲染引擎内置了PlatformView能力,可以在weex渲染的Surface上嵌入另一个Surface。 这个Surface的内容完全是由PlatformView开发者提供的。 通过这种扩展能力,Camera、Video等组件可以低成本接入,Canvas正是基于这种能力,将小程序下的Native Canvas(内部称为FCanvas)快速迁移到widget容器中。

多角度看渲染过程

更多详情请参考作者之前的文章《跨平台Web Canvas渲染引擎架构的设计与思考(含实现方案)》

就本文而言,首先我们还是从宏观的角度来看一下Canvas的大致渲染流程。 请看下图,我们从右向左看。

对于开发者来说,直接接触到Canvas API,包括w3c开发的Canvas2D API和khronos组开发的WebGL API,分别通过canvas.getContext('2d')和canvas.getContext('webgl'获取)。 JS API将通过JSBinding绑定到Native C++实现,2D将基于Skia实现,WebGL将直接调用OpenGLES接口。 图形API需要绑定平台窗口环境,即Surface,在Android端可以是SurfaceView或者TextureView。

左边是小部件容器层。 对于weex来说,渲染合成的基本单位是LayerTree,它描述了页面层次结构,记录了各个节点的绘制命令。 Canvas就是这个LayerTree中的一个Layer——PlatformViewLayer(这个Layer定义了Canvas信息的位置和大小),LayerTree通过unicorn光栅化模块合成在weex的Surface上,最后weex的Surface和Canvas都参与渲染Android 渲染管道的一部分,并由 SurfaceFlinger 合成器光栅化以显示。

以上是宏渲染链接。 下面,笔者尝试从Canvas/Weex/Android平台等不同角度描述整个渲染过程。

1 Canvas自己的观点

从Canvas本身来看,平台和容器部分可以暂时忽略。 其中有两个关键点,一是Rendering Surface的创建,二是Rendering Pipeline流程。 下面用时序图的形式展示了这个过程,总共涉及到四个线程,Platform线程(即平台UI线程)、JS线程、光栅化线程、IO线程。

Rendering Surface Setup:当收到上游创建PlatformView的消息时,会在JS线程上异步绑定Canvas API,然后在Platform线程上创建TextureView/SurfaceView。 当收到SurfaceCreated信号时,EGL环境会在Raster线程中提前初始化并绑定到Surface上。 此时Rendering Surafce就创建完成了,并通知JS线程环境Ready,可以渲染了。 与2D不同的是,如果是WebGL Context,则默认会在JS线程中创建Rendering Surace(如果未启用Command Buffer); 渲染管线概述:开发者收到Ready事件后,可以通过getContextAPI 2d或WebGL Rendering Context获取Canvas句柄并选择。 对于2D来说,开发者在JS线程调用渲染API时,只是记录渲染指令,但并不执行渲染。 真正的渲染发生在光栅化线程上。 对于WebGL,默认情况下,GL将直接在JS线程上调用。 图形API。 然而吉祥物设计,2d 和 WebGL 渲染都是由平台 VSYNC 信号驱动的。 收到VSYNC信号后,会向JS线程发送RequestAnimationFrame消息,然后才真正开始一帧的渲染。 对于2D来说,之前的渲染命令会在光栅化线程中回放,真正的渲染命令会提交给GPU,并发送swapbuffer进行显示,而WebGL会直接发送到JS线程swapbuffer中进行显示。 如果需要渲染一张图片,就会在IO线程上进行下载和解码,最后在JS或者光栅化线程中使用。

2 Weex引擎视角

从 Weex 引擎的角度来看,Canvas 是一个扩展组件。 Weex 甚至没有感知到 Canvas 的存在。 它只知道当前页面上有一个区域是通过PlatformView嵌入的。 它不关心具体内容。 所有PlatformView组件的渲染过程都是相同的。

下图左半部分描述了Weex2.0渲染环节的核心流程:通过脚本引擎执行widget的JS代码,将widget的DOM结构转换为一系列Weex渲染指令(如如AddElement创建)通过weex CallNative通用Binding接口。 Node、UpdateAttrs更新节点属性等),然后Unicorn根据渲染指令还原出一棵静态节点树(Node Tree),里面记录了父子关系、节点自身的样式&属性等信息。静态节点树会在Unicorn UI线程中进一步生成RenderObject渲染树。 渲染树通过布局、绘制等过程生成多个Layer,形成LayerTree图层结构。 LayerTree通过引擎的BuildScene接口发送到光栅化模块进行合成,最终渲染到Surface上,并通过SwapBuffer发送到显示。

右半部分是Canvas的渲染过程。 Canvas的视角在大体流程中已经介绍过,这里不再赘述。 这里重点关注Canvas的嵌入方案。 Canvas是通过PlatformView机制嵌入的,会在Unicorn中生成相应的Layer来参与后续的合成,但是PlatformView有多种实现方案sketchup渲染器在哪里打开,并且每种方案的流程都有较大差异,下面我们就来说一下。

Weex2.0在Android平台上提供了多种PlatformView嵌入式技术解决方案。 其中有两个:VirtualDisplay 和 Hybrid Composition。 此外,还有自主研发的挖孔解决方案。

虚拟显示

在这种模式下,PlatformView内容最终会被转换为外部纹理来参与Unicorn合成过程。 具体流程:首先创建一个SurfaceTexture并存储在Unicorn引擎端,然后创建android.app.Presentation,并使用PlatformView(如CanvasTextureView)作为Presentation子节点并渲染到VirtualDisplay。 我们都知道VirtualDisplay需要提供一个Surface作为Backend,所以这里的Surface是基于SurfaceTexture创建的。 当SurfaceTexture填充内容时,引擎端收到通知并将SurfaceTexture转换为OES纹理,参与Unicorn光栅化过程,最后与其他Layer合成到Unicorn对应的SurfaceView或TextureView。

该模式的性能尚可,但主要缺点是无法响应 Touch 事件、失去 a11y 功能以及无法获取 TextInput 焦点。 正是由于这些兼容性问题,使得该方案的应用场景相对有限。

混合成分

在此模式下,widget 不再渲染到 SurfaceView 或 TextureView,而是渲染到与 android.media.ImageReader 关联的一个或多个 Surface。 Unicorn基于ImageReader封装了一个Android自定义View,并使用ImageReader产生的Image对象作为数据源,不断将其转换为Bitmap参与Android原生渲染过程。 那么,为什么可以有多个 ImageReader 呢? 由于布局层叠的可能性,PlatformView的顶部和底部可能存在DOM节点。 相应的,PlatformView本身(比如Canvas)不再转换成纹理,而是像普通View一样参与Android平台的渲染过程。

Hybrid Compositing模式解决了VirtualDisplay模式的大部分兼容性问题,但也带来了新的问题。 这种模式有两个主要缺点。 一是需要合并线程。 PlatformView启用后,Raster线程的任务会丢给Android主线程执行,增加了主线程的压力; 二是基于ImageReader封装的Android原生View(即下面提到的UnicornImageView)需要不断创建和绘制Bitmap,尤其是Android 10之前,需要通过软件拷贝的方式生成Bitmap。 性能有一定的影响。

整体来看,Hyrbid Compositing具有更好的兼容性,因此当前引擎默认使用该模式来实现PlatformView。

3 Android平台视角

接下来,笔者尝试从Android平台的角度重新审视这个过程(以Weex + Hybrid Compositing PlatformView模式为例)。

如上所述sketchup渲染器在哪里打开,在 Hybrid Compositing 模式下,widget 被渲染到一个或多个 Unicorn ImageView,按照 Z-index 从上到下排列是 UnicornImageView(Overlay) -> FCanvasTextureView -> UnicornImageView(Background) -> DecorView,然后从从Android平台来看,视图结构如上图所示。 weex根视图(UnicornView)嵌套在Android根视图DecorView下面吉祥物设计,其中包含多个UnicornImageView和一个FCanvasPlatformView(TextureView)。

从平台的角度来看,我们甚至不需要关心UnicornImageView和FCanvas的内容,我们只需要知道它们都继承自android.view.View并遵循Android原生的渲染流程即可。 原生渲染由VSYNC信号驱动,通过ViewRootImpl#PerformTraversal顶层函数触发Measure、Layout、Draw流程。 以绘图为例,消息首先分发到根视图DecorView,自上而下的Dispatch(dispatchDraw)依次回调各个View的onDraw函数。

对于FCanvas PlatformView来说,它是一个TextureView,本质上是一个SurfaceTexture。 当SurfaceTexture发现有新内容填充其内部缓冲区时,会触发frameAvailable回调通知视图invalidate,然后通过updateTexImage将SurfaceTexture传输到Android渲染线程。 是一个纹理,由系统合成; 对于UnicornImageView来说,它是一个自定义View,本质上是对ImageReader的封装。 当ImageReader关联的Surface内部缓冲区被填满时,可以通过acquireLatestImage获取最新的帧数据。 UnicornImageView#onDraw中,是将最新的帧数据转换为Bitmap,交给android.graphics.Canvas进行渲染。

而Android自己的View Hierarchy也关联着一个Surface,通常称为Window Surface。 上述View Hierarchy经过绘制过程后,会生成一个DisplayList,Android渲染线程通过HWUI模块解析该DisplayList,生成实际的图形渲染指令,交给GPU进行硬件渲染。 最终内容绘制到上述Window Surface上,然后与其他Surface(如Status bar、SurfaceView等)结合通过系统SurfaceFlinger合成到FrameBuffer中,最终显示在设备上。 以上是从Android平台角度的渲染流程。

总结与展望

经过以上多个角度的分析,相信读者已经对渲染流程有了初步的了解。 这是一个简短的总结。 Canvas作为Widget的核心能力,是由weex内核的PlatformView扩展机制支持的。 这种松耦合、可插拔的架构模式一方面可以让项目敏捷迭代,让Canvas能够快速实现新场景下的业务赋能,另一方面也让系统更加灵活、可扩展。

但同时读者也可以看到PlatformView本身存在一些性能缺陷,性能优化是我们后续演进的目标之一。 下一步,我们将尝试将 Canvas 与 Weex 内核渲染管线深度集成,让 Canvas 与 Weex 核心共享 Surface,不再通过 PlatformView 扩展嵌入。 另外,对于交互小部件,我们未来还会提供更加精简的渲染链接,敬请期待。

关注【阿里巴巴移动技术】微信公众号,每周3个移动技术实践&干货供你思考!

最后编辑:
作者:nuanquewen
吉祥物设计/卡通ip设计/卡通人物设计/卡通形象设计/表情包设计