Filament 渲染引擎剖析 之 多线程渲染 2
Filament 渲染一帧流程
Filament 是一款针对多核硬件系统开发的并行渲染引擎,内部通过多线程的合理调度,尤其在android移动平台上针对大小核心架构做了很多优化设计,比如通过设置线程亲和力,大核心执行繁重的渲染任务,每个小核心上执行一个工作线程对场景对象做排序、剔除等工作,这一模型极大的提高了系统的渲染效率。从多线程渲染架构来讲, Filament 多线程的组织方式还是比较先进的,尤其使用了多线程 + forward claster rendering 渲染方案,支持数量庞大的光源。
上图描述了使用Filament 渲染引擎绘制场景时,绘制一帧的大概流程,渲染工作是由渲染器的render方法来完成, 详细说明的代码如下:
if (renderer->beginFrame(window->getSwapChain())) {for (filament::View* offscreenView : mOffscreenViews) {renderer->render(offscreenView);}for (auto const& view : window->mViews) {renderer->render(view->getView());}renderer->endFrame();
Filament 命令绘制模型
Filament 为支持高效的多线程并发/并行渲染,场景图并未按传统的层次结构来组织,而是将场景对象的组织扁平化,用一维数组的形式来管理, transform 组件以链表的形式表达父子变换空间关系,这一数据结构切断了父子节点间的空间遍历、依赖关系,为场景图的并行渲染提供了可能,也为支持vulkan , openGL,matel驱动提供了通用的框架, 场景节点的表示如下图:
![](/assets/blank.gif)
Filament 对场景的渲染主要分为两个阶段:
对场景节点进行划分,以“分治”策略创建多个工作Job实例添加到JobSystem 作业队列中,每一次对图形API的调用都会生成相应的渲染命令添加到 commandBuffer 缓冲区中;
设备线程通过引擎flush接口被唤醒,从命令队列commandBuffer中取出命令逐个执行,这一步是真正调用图形API绘制的过程。
Filament 多线程渲染架构
Filament 多线程架构类似于Java 的Doug Lea在JDK7中引入了的Fork/Join框架, 它是一种基于"分治"思想的计算框架。Filament的工作线程会对自己的任务按照一定的粒度进行拆分,一个大任务拆分成多个子任务之后,子任务放入工作队列中等待执行。任务的划分是以递归深度和节点个数为阀值,当一个线程的工作队列为空时,该线程如果被唤醒,它可以从其它线程的工作队列中steal任务Job执行, 采用了工作窃取算法"work-stealing"来组织渲染任务的分配 。Filament 线程创建、管理、调度由JobSystem类负责。
JobSystem 线程管理器的主要工作原理:
系统启动时,如果用户没有配置线程运行环境,作业系统会根据CPU硬件的核心个数创建多个工作者线程,并设置线程的亲和力,这些任务会被设置到CPU小核心上运行,其中系统主线程被添加到作业系统线程池的队尾,成为"协程",系统中有绘制任务Job 时,首先添加到系统主线程的工作队列中,主线程也负责执行渲染工作任务Job,各个工作者线程空闲时会“窃取” 系统主线程工作队列中的任务Job去执行。JobSystem 提供一系列的线程及任务管理接口来管理作业,并对线程调用提供同步操作,比如runAndWait 接口,只有执行完当前所有的任务及其子任务时,线程才会从阻塞状态退出。
JobSystem的每个工作线程都维护着一个双端工作队列(WorkQueue)。
每个工作线程在运行中添加先的作业任务时,会放入工作队列的队尾,并且工作线程在处理自己的工作队列时,使用的是"LIFO"方式,也就是说每次从队尾取出任务来执行。
每个工作线程在处理自己的工作队列同时,会尝试窃取一个任务,窃取的任务位于其他线程的工作队列的队首,也就是说工作线程在窃取其他工作线程的任务时,使用的是 FIFO 方式。
在既没有自己的Job,又没有可以窃取的Job时,作业线程进入休眠。
![](/assets/blank.gif)
Filament 的三个主要线程组:
Filament 在运行时,根据线程功能及所处环境,这里抽象成三个主要线程组,分别为 系统主线程, 多个作业线程, 驱动线程。
系统主线程功能是创建作业任务并将其追加到自己的作业队列,执行作业任务;
作业线程 ,作业线程可以有零个或多个,如果硬件CPU为单核就不会创建作业线程,作业线程从系统主线程或其它线程中"窃取"渲染作业任务Job并执行。这里有一个很有意思的情况,工作者线程切取任务来执行时并不是直接从系统主线程任务队列中窃取,而是使用随机算法从各个线程任务队列中窃取,但JobSystem 添加任务时总是将任务追加到主线程工作队列里。
驱动线程,如果系统支持多线程渲染, 在FEngine 初始化时引擎会创建一个驱动线程用来单独执行绘制任务,如果是移动设备,该线程会在大核上运行来执行繁重的渲染命令来绘制实体。
![](/assets/blank.gif)
总之,Filament 执行渲染命令并不是像传统渲染方式那样直接调用硬件图形API,而是以命令对象的方式record, 生成一个命令队列,每个命令对象记录渲染所需硬件资源及GPU端 API 调用过程(也就是绘制函数),当这些命令准备就绪后 , Filament 驱动线程被唤醒,逐个执行渲染命令(也就是调用绘制函数)。 这种设计模式有其自身的好处,使硬件驱动层与应用层的隔离,而且增加了系统底层API可扩展性,缺点是实现复杂。 Filament 使用了自己的内存池,每个类对象(包括命令对象)的内存分配都要考虑字节对齐和精打细算。
Filament 渲染引擎剖析 之 多线程渲染 2相关推荐
- Filament 渲染引擎剖析 之 创建渲染对象 1
Filament 渲染对象的创建 Filament 将实体(Entity)属性看成组件(component)的形式,实体可以是相机,光源,可绘制实体, 全局光照(IBL)实体等类型.一个场景包含最多. ...
- Filament渲染引擎剖析 之 通过图元构建几何体
Filament渲染引擎剖析 之 通过图元构建几何体 什么是图元 filament可绘制的图元类型 构建图元的工具 VertexBuffer IndexBuffer Primitive 什么是图元 图 ...
- Filament 渲染引擎剖析 之 FrameGraph 1 虚拟资源的定义与创建
Filament 使用了可扩展渲染管线(FrameGraph)来组织渲染通道和管理渲染资源,网上也搜了下可扩展渲染管线的相关的文章,一般认为可扩展渲染管线是次时代渲染引擎应该具备的比较先进的管线组织架 ...
- Filament 渲染引擎剖析 之 FrameGraph 2 动态构建渲染管线
一.渲染通道的设计与实现 1 Frostbite 构建FrameGraph的准则 我们先看下Frostbite 构建FrameGraph原则,包括三个阶段: 设置阶段 setup.编译阶段compil ...
- pyqt创建窗口没有句柄_Filament 渲染引擎剖析 之 FrameGraph 1 虚拟资源的定义与创建...
Filament 使用了可扩展渲染管线(FrameGraph)来组织渲染通道和管理渲染资源,网上也搜了下可扩展渲染管线的相关的文章,一般认为可扩展渲染管线是次时代渲染引擎应该具备的比较先进的管线组织架 ...
- 高性能跨平台渲染引擎系列一: 跨平台渲染引擎简介
引言: 一直工作比较忙,很久就想写点东西做个备忘,拖延至今.本系列也期望督促自己坚持记录分享,文中如有笔误或者理解偏差,欢迎各位指正交流.也期望未来基于该系列文章的相关代码同步到git上,最终完成一款 ...
- Cryengine渲染引擎剖析
ms,OpenGPU这些天又冷下去了, 转篇Napoleon314 大牛的分析,排版好乱,见谅,耐心读,这是个好东西,注意看他自己的实现,是个技术狂人啊,Ogre焕发次时代的光芒啊~~~努力 ---- ...
- Filament 渲染引擎剖析 之 ECS模式
一.什么是 ECS 模式 ECS Entity-Component-System(实体-组件-系统) 是基于组合优于继承原则的一种模式,每一渲染对象都是一个实体,每个实体由一个或者多个组件构成,每个组 ...
- 浅析渲染引擎与前端优化
本文以 Chrome 浏览器的内核 WebKit(更确切是 WebKit 分支 Blink,以下统称为 WebKit )为例,对渲染引擎如何展示页面做个简单.全面的了解. 本文主要是两方面内容: 浅析 ...
最新文章
- 觉SLAM的主要功能模块分析
- [综合面试] 计算机面试书籍与求职网站推荐
- 大话网站---从Hello World到高并发网站
- HTML5----简易贪吃蛇小游戏
- 新版本Chrome同源策略、跨域问题处理No ‘Access-Control-Allow-Origin‘ header is present on the requested resource.
- 浅谈最近发布的金融行业多方安全计算的技术标准
- 【职场】遇到了个失业开滴滴的程序员
- 华为AR engine 应用开发学习教程
- 《商业智能BI白皮书3.0》正式发布(附下载链接)
- java中break和return的区别_java 中return和break的区别
- android 显示Gift图片
- Java引用类型分析
- Python TCP 学习笔记
- 分布式存储 HDFS原理
- C++ typedef 用法详解
- SEGY数据的读取与写出C++
- 一个人的行动力,取决于他的底层信念。
- 信息论 | 计算离散信源的信息量和熵的MATLAB实现(函数封装调用)
- 大一C语言总结贴(持更) Part1 输出菱形
- 钢铁企业如何分步实施信息化
热门文章
- java鸡兔同笼用循环_Java使用for循环解决经典的鸡兔同笼问题示例
- jekenis+tomcat部署更新war失败【踩坑日记】
- InputStream和FileInputStream
- iPhone打开个人热点的时候提示“请联系carrier”的解决方法
- 西门子精智HMI-TP1200发邮件功能
- Java 超全面试题
- python开发的gui界面,python写gui应用程序
- 【数据结构】单链表逆序
- 利用go-ethereum创建自己的以太坊账户
- ADI Blackfin DSP处理器-BF533的开发详解59:DSP控制ADXL345三轴加速度传感器的应用2(含源码)