从零开始的跨平台渲染引擎(零)——基础架构分析与设计
Posted 董小虫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零开始的跨平台渲染引擎(零)——基础架构分析与设计相关的知识,希望对你有一定的参考价值。
本文同时发布于本人的知乎专栏:https://zhuanlan.zhihu.com/p/403395505
前言
近几年我的工作主要集中在渲染引擎方面。随着工作时间的增长,接触和学习到的相关知识也逐渐增多,并且有着渐渐变杂的趋势。我也想着我所掌握的对相关知识进行总结,将这些知识串联起来,形成体系。于是,从本篇文章开始,我打算从零开始,一步步搭建一个跨平台的渲染引擎,并就着代码逐步总结。
本篇文章将对跨平台渲染引擎做了简要的需求分析,以及基础架构的简要设计。
需求分析
- 跨平台:需要符合“一次编写,随处运行”的主旨;在现在初始阶段,首先选择移动端的两大主流平台android和ios来实现,后续会考虑适配Windows、WASM。(MacOS和iOS的实现比较接近,可以在完成iOS端的同时进行适配)
- 嵌入式:非独立运行的应用,由其他应用以控件的方式将引擎嵌入;
- 提供脚本运行时环境:对上层开发者(如游戏开发者等)提供脚本接口,如javascript或Lua等。
技术分析
有了大概的引擎需求,现在我们开始分析一下需要什么样的技术栈来实现这些需求。
整体的技术架构
渲染引擎的整体架构如下图所示:
- 底层的Platform层对应着各个系统平台,如Android、iOS、Web、Windows等。
- Container层对应着系统平台容器层。其作用是抹平系统API差异,并使引擎可以运行与各个平台上。
- Graphic Engine层和Graphic Wrapper层对应着图形引擎及其包装。其作用是底层的图形绘制,以及向上提供绘制接口。图形引擎包括但不限于:OpenGL、Metal、Vulkan等。
- Script Engine和Runtime Wrapper层对应脚本引擎及其包装。其作用是解析运行脚本,向上提供脚本运行接口及扩展API能力。脚本引擎包括但不限于:V8、JSCore、WASM、QuickJS等。
- Framework层是引擎的核心层,其作用是物理引擎模拟、Action计算、渲染指令生成等。
- Export API是向上层开发者提供的API接口。上层开发者可用脚本语言,利用这些API进行业务逻辑开发。
下面对各层进行详细分析。
图形引擎
首先,底层的图形引擎我优先选择使用OpenGL,因为OpenGL在平台的适配性上优势比较明显。尤其在初期版本,搭建引擎整体架构时,需要尽量减少适配性的工作。
当然,现在Metal、Vulkan等引擎也在逐步的代替古老的OpenGL。所以,在后续版本迭代中,会将适配不同的图形引擎。这也是架构中Graphic Wrapper层存在的意义。
OpenGL
OpenGL全称为Open Graphic Library,是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API)。
OpenGL接口类似C语言函数,但其实是语言独立的。因此,OpenGL会有很多不同语言的绑定,如:Android提供Java和C绑定、iOS提供C绑定,甚至JavaScript绑定的WebGL。OpenGL不仅语言无关,而且平台无关。规范只字未提获得和管理OpenGL上下文相关的内容,而是将这些作为细节交给底层的窗口系统。
针对手机、PDA和游戏主机等嵌入式设备,Khronos组织又从OpenGL中裁剪定制了OpenGL ES(全称为OpenGL for Embedded Systems)。其中OpenGL ES 2.0是参照 OpenGL 2.0 规范定义的,引入了对可编程管线的支持。
由于OpenGL依赖于硬件的支持,所以在OpenGL版本选择的考虑中,为了适配较老的硬件机型,这里选择使用OpenGL/OpenGL ES 2.0版本。同时也应该考虑适配3.0版本,以用于后续更新。
Metal
Metal是苹果公司于2014年推出的新的图形引擎,其拥有更高效的图形渲染性能。Metal引擎对软硬件有一些要求,如果使用Metal引擎,要求系统版本不低于iOS 8或MacOS 10.11,硬件则是需要A7芯片以上。
苹果曾在18年的WWDC大会上宣布在MacOS 10.14、iOS 12等版本之后,将逐步废弃OpenGL。虽然当前仍然可以使用OpenGL,不过不再继续更新,并且不推荐使用。所以在后续的适配工作中,也会考虑到在iOS平台上使用Metal等情况。
Vulkan
Vulkan是由Khronos组织在2015年推出的一种高级图形API。Vulkan的设计初衷是为了避免在上层API出现更高的开销。同时,还希望Vulkan成为一个比其他图形API更跨平台的API,它不仅针对高端系统,还针对低端移动设备。
同样的,Vulkan也有最低软硬件要求。软件上,Android 7.0开发者预览版开始,Google在系统平台中添加了对Vulkan的API支持。硬件上,则需要AMD Radeon Software Crimson 版 16.3 及更新版本在 Windows® 7、Window® 8.1、Windows® 10 和 Linux® 中支持基于次世代图形核心架构的以下 AMD APU 和 Radeon™ 显卡。
平台容器控件
平台容器控件用于承载引擎本身,并起到引擎和系统之间的桥梁作用。
Android
在Android系统中,存在两种控件可以满足自定义渲染能力,分别是:SufaceView
和TextureView
。
SurfaceView
和TextureView
都继承于View
,可以作为普通的View
嵌入到视图层次结构中。但和普通的View
区别在于,他们拥有自己独立的Surface
。而这个Surface
就是我们引擎渲染绘制的载体。这两种View
的区别在于,SurfaceView
会在SurfaceFlinger
中开启一个独立的Layer来绘制。而TextureView
则和DecoView
处于同一个Layer中,所以画面更新是和视图结构同步进行的。在实际使用中,则需要根据实际情况来选择其中一个View
来作为视图载体。
Surface
在Android的EGL环境中可以通过ANativeWindow_fromSurface
创建ANativeWindow
。并在此window
基础上,创建EGLSurface
和EGLContext
,作为OpenGL的绘制环境。
iOS
在iOS平台上,直接继承UIView
即可,只需要在类型实现中添加:
+ (Class)layerClass
return [CAEAGLLayer class];
用于告诉系统当前的View
的Layer
将作为OpenGL的绘制层。执行下列代码,将此Layer绑定到渲染线程的EAGLContext
上。
[EAGLContext setCurrentContext:context];
// ...
[context renderbufferStorage:GL_RENDERBUFFER
fromDrawable:layer];
脚本运行时
跨平台引擎的脚本语言,较常用的是JavaScript和Lua。在脚本语言的选择问题上,这里选择使用JavaScript。原因有一下几点:
- Lua更容易上手,但是JavaScript则拥有更大的用户基数和完善的生态环境;
- JavaScirpt有TypeScript这个超集,开发效率更高;
- JS是Web端的原生语言,在向Web端适配时更容易;
- 在iOS平台上,JS可以利用其内置的JavaScriptCore实现JIT。
主流的JavaScript引擎主要有V8、JavaScriptCore以及前两年由Fabrice Bellard大神写出的QuickJs,这几种JS引擎各有优劣。可以从一下几个角度来对各种引擎考量:
- 性能
- 体积
- 语法支持度
- 调试便捷性
- 应用市场平台规范
此处可参考文章:🤔 移动端 JS 引擎哪家强?美国硅谷找…这里就不再过多赘述。
根据各项条件,这里选择在iOS平台使用JavaScriptCore,在Android平台使用QuickJs。
- iOS平台选择JavaScriptCore这点基本没什么可犹豫的,因其主场优势,可直接依赖系统级框架,减小包体积,开发难度也减小很多。当然,也存在一些缺陷,JSC在三方应用直接引用时,JIT因安全原因是默认关闭的。而且因为是系统级框架,语法支持度则是根据系统版本来决定的,例如:iOS 9以下是不支持ArrayBuffer的。
- Android平台选择QuickJs。其实从性能的角度来说,在Android平台上使用V8是最好的。但是作为嵌入式引擎,包体积是一个很重要的考量标准。我在编译V8的8.x版本时发现arm64架构下的动态库甚至可以达到14M,这对于一个嵌入式引擎来说,有些巨大。所以这里选择使用QuickJs,虽然没有JIT,但是如果没有太多的CPU密集计算的话,性能上是可以接受的。
Framework和接口
Framework是渲染引擎的核心,承担起物理模拟、布局排版、渲染指令生成等任务。Export API则是向上层开发者提供的API接口。上层开发者可用脚本语言,利用这些API进行业务逻辑开发。
这两层的更新迭代频率会比较高,基本上会在引擎迭代过程中不断的变化。所以我打算在后续引擎搭建的过程中,再对这两块进行详细的分析。
总结
本篇文章主要对跨平台渲染引擎做了简要的需求分析,以及基础架构的简要设计。后续文章将结合实际代码,一步步从零开始搭建起整个引擎。
以上是关于从零开始的跨平台渲染引擎(零)——基础架构分析与设计的主要内容,如果未能解决你的问题,请参考以下文章