App的启动过程(10)surfaceflinger对数据合成,送显

2023-11-05

下面就是SurfaceFlinger执行实际的数据合成,然后刷新到屏幕上。

voidSurfaceFlinger::onMessageReceived(int32_t what) {

         switch(what) {

         case MessageQueue::INVALIDATE: {

         bool refreshNeeded =handleMessageTransaction();

         refreshNeeded |=handleMessageInvalidate();

         refreshNeeded |=mRepaintEverything;

         if (refreshNeeded) { signalRefresh();}

Break;

}

case MessageQueue::REFRESH: {

         handleMessageRefresh();

         break;

}

}

}

上面是surfaceflinger收到vsync时的处理代码,signalRefreshhandleMessageRefresh是一样的,所以INVALIDATEREFRESH多了两个函数:handleMessageTransaction(对layer属性变更的处理)和handleMessageInvalidate(数据的刷新),在看handleMessageRefresh包含了那些工作:

void SurfaceFlinger::handleMessageRefresh(){

         preComposition();//合成前的准备

         rebuildLayerStacks();//重建layer堆栈

         setUpHWComposer();//hwcomposer的设定

         doComposition();//正式的合成处理

         postComposition(refreshStartTime);//合成后期的处理

}

         整个UI的就是上面handleMessageRefresh中几个函数,加上INVALIDATE中那两个函数。

Step1handleMessageTransaction

         handleMessageTransaction真正处理业务的地方是handleTransactionLocked

voidSurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags){

         if(transactionFlags & eTraversalNeeded) {

                   for(size_t i=0 ; i<count ; i++) {

const uint32_t flags = layer->doTransaction(0); }

         }

         commitTransaction();

}

transactionFlags有多个类别,这里以eTraversalNeeded为例,首先会循环判断每个layer是否要doTransaction,如果需要就调用layer->doTransaction由各layer做内部处理。

uint32_t Layer::doTransaction(uint32_tflags) {

//尺寸发生变化,调用setDefaultBufferSize使它生效,SurfaceFlingerConsumer,可以这样理解:surfaceflinger作为buffer的消费者,并没有直接管理Buffersurfaceflinger直接拥有的是跟存储图层数据有关的layer,而layer也没有直接持有BufferQueue对象,而是通过SurfaceFlingerConsumer来管理,

         if(sizeChanged) {

mSurfaceFlingerConsumer->setDefaultBufferSize(c.requested.w,c.requested.h); }

//重新计算可见区域,这个要作为flags传给surfaceflinger统一部署

         if(s.active != c.active) {

flags |= Layer::eVisibleRegion; }

//layerpositionz-ordertransparentregioncrop等属性变化时,mCurrentState::Sequence的值就会递增,在doTransaction时,它和mDrawingState::sequence的值就不一样了,它在平时收集属性的变化,到vsync信号产生时做统一处理。mCurrentStatemDrawingState分别表示当前的状态和上一次drawing时的状态。Surfaceflinger中也有两个这样的变量,但是数据结构不同,surfaceflinger中的mCurrentState,内部包含了一个变量:LayerVector layersSortedByZ;记录了所有按Z-order顺序排列的layers

         if(c.sequence != s.sequence) {

this->contentDirty = true; }

//mCurrentState赋值给mDrawingState,

commitTransaction(c);

}

         完成所有layer的遍历后,返回到handleTransactionLocked

voidSurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags){

//有新增的layer,可见区域要重新计算,同样还有移除layer的处理

         if(currentLayers.size() > layers.size()) {

                   mVisibleRegionsDirty= true;}

//结束业务处理,会回调被移除layeronRemoved(),最后通过mTransactionCV.broadcast();唤醒等待Transaction结束的线程,如应用进程中的处理surface跟新的线程、surfaceflinger中的显示线程。

         commitTransaction();

}

Step2,handleMessageInvalidate--界面重新绘制,这个函数处理bufferQueue相关的工作。

bool SurfaceFlinger::handleMessageInvalidate(){

returnhandlePageFlip();

}

bool SurfaceFlinger::handlePageFlip(){

//锁定一个buffer,也就是每个layer当前要处理的缓冲区

const Regiondirty(layer->latchBuffer(visibleRegions));

//更新displayDevice中的脏区域

invalidateLayerStack(s.layerStack,dirty);

}

Region Layer::latchBuffer(bool&recomputeVisibleRegions){

if(mQueuedFrames > 0 || mAutoRefresh) {

status_t updateResult =mSurfaceFlingerConsumer->updateTexImage(&r,

mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,

mLastFrameNumberReceived);

                 mFlinger->signalLayerUpdate();

                 mActiveBuffer= mSurfaceFlingerConsumer->getCurrentBuffer();

}

}

status_tSurfaceFlingerConsumer::updateTexImage(...){

err =acquireBufferLocked(&item, computeExpectedPresent(dispSync),...);

}

前面说过,当应用进程填充好一块buffer后,会通过BufferQueue的方法queue把这个bufferslot入队,同时BufferQueue会调用onFrameAvailable通知消费者有一帧数据准备好了,可以消费了,继承FrameAvailableListener这个监听的消费者--layer的方法onFrameAvailable就会被调用,这个函数会增加mQueuedFrames的计数,也会向surfaceflinger发去一个invalidate信号。LayerBufferQueue的管理是通过SurfaceFlingerConsumer实现的,这个消费者想要操作一块buffer,要先accquire它,这个操作封装在mSurfaceFlingerConsumer->updateTexImage()中,accquire到的buffer封装在BufferItem中,如果有多个mQueuedFrames,还会通过signalLayerUpdate组织一次新的invalidate,最后更新当前活跃的缓冲区mActiveBuffer

Step3,预合成--合成前的准备,preComposition

void SurfaceFlinger::preComposition()

  const LayerVector& layers(mDrawingState.layersSortedByZ);

  for (size_t i=0 ; i<count ; i++) {

    if (layers[i]->onPreComposition()) {

      needExtraInvalidate = true;

  if (needExtraInvalidate) {

    signalLayerUpdate();

首先得到当前所有layer的集合,然后调用每个layer的预合成接口onPreComposition,只要有一个layer中存在被QueuedFrames,即mQueuedFrames>0,那么needExtraInvalidate就会变成true,最后触发signalLayerUpdate()调用,通过EventThread安排一次vsync

Step4,计算可见layer及它们的可见区域—rebuildLayerStacks

void SurfaceFlinger::rebuildLayerStacks() {

//当前所有的layers都是通过mDrawingState.layersSortedByZ来记录的,每个layer都有一个layerStack来区别它属于哪个Display

         constLayerVector& layers(mDrawingState.layersSortedByZ);

//系统的Display可能不止一个,都存储在mDisplays中,逐个处理这些Display

         for(size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {

                   if(hw->isDisplayOn()) {

//根据所有layers的当前状态,计算dirtyRegion—需要重新绘制的区域,opaqueRegion—不透明区域。

                            computeVisibleRegions(hw->getHwcDisplayId(),layers,

                                     hw->getLayerStack(),dirtyRegion, opaqueRegion);}

                   for(size_t i=0 ; i<count ; i++) {

                            constsp<Layer>& layer(layers[i]);

//把需要绘制的layer添加到layersSortedByZ中。

                            layersSortedByZ.add(layer);

         }

}

Step5,为合成搭建环境—setUpHWComposer

把需要显示的那些layer的数据准备好,报给Hwc模块来决定由谁进行最终的合成工作。

void SurfaceFlinger::setUpHWComposer() {

//这个HWComposer并不是真正的Hal模块,而是surfaceflinger为管理HWComposer模块而设计的一个类,路径是:frameworks/native/service/surfaceflinger/displayhardware/   HWComposer& hwc(getHwComposer());

//依次处理各个Display,构造WorkList

         for(size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {

sp<const DisplayDevice> hw(mDisplays[dpy]);

const int32_t id = hw->getHwcDisplayId();

const Vector< sp<Layer> >&currentLayers(hw->getVisibleLayersSortedByZ());

const size_t count = currentLayers.size();

if (hwc.createWorkList(id, count) == NO_ERROR) {…}

}

//填充各个layer的数据,由每个layer自己完成。

layer->setPerFrameData(hw,*cur);

//合成过程既可以有Hwc模块完成,也可以通过OpengGlEs来完成,具体用哪种方式是有prepare()中的compositionType来决定的。

status_t err =hwc.prepare();

}

Step6,执行合成、显示到屏幕上—doComposition

void SurfaceFlinger::doComposition() {

//逐个Display去处理,对每个DisplayDevice,需要单独调用doDisplayComposition

         for(size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {

                   doDisplayComposition(hw,dirtyRegion);

//通知hwc合成已经完成。

                  hw->compositionComplete();

         }

         postFramebuffer();

}

void SurfaceFlinger::doDisplayComposition(…){

//相关layer的数据合成。

         doComposeSurfaces(hw,dirtyRegion);

//交换前后台数据,将UI数据显示到屏幕上的关键是eglSwapBuffers

         hw->swapBuffers(getHwComposer());àeglSwapBuffers(mDisplay, mSurface);

}

bool SurfaceFlinger::doComposeSurfaces(…){

         boolhasGlesComposition = hwc.hasGlesComposition(id);

//需要openglEs合成,通过makeCurrent设置当前的渲染环境。

         if(hasGlesComposition) {

                   hw->makeCurrent(mEGLDisplay,mEGLContext);

//需要Hwc执行合成layerhasHwcCompositionhasGlesComposition不是互斥的,他们有可能同时为true,这种情况说明既有要OpengGlES处理的layer,也有要Hwc处理的layer。对layer的处理:layer->draw(hw, clip)àLayer::onDraw();

                   constbool hasHwcComposition = hwc.hasHwcComposition(id) ||

                            isS3DLayerPresent(hw);

                   if(hasHwcComposition) {

                            engine.clearWithColor(0,0, 0, 0);}

}

}

// doComposition的最后调用了这个函数,核心功能是调用Hwc模块的hal接口set,把那些需要hwc处理的layer的数据传给hwc做实际的处理,set的内部也调用了eglSwapBuffers

void SurfaceFlinger::postFramebuffer(){

         hwc.commit();àmHwc->set(mHwc, mNumDisplays, mLists);

}

到这里数据就送到了显示设备。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

App的启动过程(10)surfaceflinger对数据合成,送显 的相关文章

  • Interlocked.CompareExchange 可以抛出 NullReferenceException 吗?

    From https msdn microsoft com en us library bb297966 v vs 110 aspx https msdn microsoft com en us library bb297966 v vs
  • Zeppelin:如何在 zeppelin 中重新启动 SparkContext

    我正在使用 zeppelins Spark 解释器的隔离模式 在这种模式下 它将为 Spark 集群中的每个笔记本启动一项新工作 我想在笔记本执行完成后通过 zeppelin 终止该作业 为此我做了sc stop这停止了 sparkCont
  • Pandas 如何删除包含所需字符串的行

    我想删除包含所需字符串的所有行 假设我有以下数据框 A B C 1 a x w g n 3 l p j p v 我想删除包含字符串的所有行p 我已经搜索过它 但大多数答案都是基于列名称 就我而言 我不会知道它可以出现在任何列中 输出数据帧应
  • 如何用纯色填充位图?

    我需要使用唯一的 RGB 颜色创建 24 位位图 分辨率 100x100 像素 并将生成的图像保存到磁盘 我目前使用的是SetPixel http msdn microsoft com en us library 6c7eyzyb aspx
  • 在 Google App Engine 数据模型中进行“OR”查询

    我想进行这样的查询 从地址 或年龄 的人中选择名称 这在GAE模型中可能吗 所有事物都包含 AND 闭包 而不是 OR 我如何使用 JDO JPA Objectify 来做到这一点 提前致谢 数据存储上没有 OR 运算 您必须执行两个单独的
  • Hibernate 对于 Android 应用程序来说是一种杀伤力吗? [复制]

    这个问题在这里已经有答案了 我正在为我的 Android 应用程序寻找一个好的 ORM 乍一看似乎对于移动设备我更喜欢使用更简单的东西 问题是我只是在这里假设 没有真正的证据 所以我想我应该询问社区的意见 也许有人有过这样的经历 它是一个相
  • 并行运行 Angular 和 AngularJS 框架

    我找到了描述如何将 Angular 2 组件集成到 AngularJS 中的资源 但所有这些都涉及像 Angular 项目一样设置 AngularJS 项目 需要 TypeScript 的转译器 需要 ES6 需要 import 语句 我想
  • Ext lib 对话框和文件上传控件

    我有一个包含文件上传控件的对话框 当在对话框中提交表单时 除所选文件之外的所有内容都会正确保存 我怀疑对话是造成这种情况的原因 我是否必须设置一个属性才能启用它 或者是否有某种解决方法 I think this http www domin
  • Qt 按键事件 Enter

    void LoginModle keyPressEvent QKeyEvent event qDebug lt lt event gt key lt lt t lt lt Qt Key Enter lt lt t lt lt QKeyEve
  • 在 VBA 中调用批处理文件无法正常工作

    我正在尝试创建一个可供其他人使用的程序 目前 我的文件位于目录中C Documents and Settings jpmccros Desktop test 该目录包含我的macro xlsm names bat 还有另一个子目录名为Dat
  • QTextEdit:仅当滚动条位于底部时自动向下滚动

    有一个 QTextEdit 显示相当多的文本 它不可编辑 假设我想在开头阅读一些内容 向上滚动 但随后添加了一个新行 并且滚动条自动转到底部 我在使用各种程序时遇到类似的问题 无论它们是用什么语言编写的 如何处理这个问题 当向文本添加新行时
  • 高效编写航空公司路由算法

    Given 航班数据库 出发城市 到达城市 出发时间 到达时间 问题 如果出发时间不重要 那么在两个城市之间列出服务的最有效算法是什么 考虑到我们想要最小化中途停留时间 但仍高于标称最小值 即 20 分钟 并最小化中途停留次数 如果有直达航
  • 哪种 LaTeX 包与 knit 一起使用以获得更多的表格控制?禁忌?

    我正在用 knitr 写一张更长的桌子xtable和tabular environment longtable 在 longtable 包中时print将它们纳入我的 Rnw file 问题是我对longtable环境控制不够 我有一些文本
  • LISP - 破坏性和非破坏性构造

    正确的定义是什么破坏性的 and 非破坏性的在 LISP 或一般情况下 中构造 我试图寻找真正的含义 但我只发现了这些术语的很多用法 而没有真正解释它们 据我了解 通过破坏性的函数是指一个函数 它改变构造 或变量 的含义 所以当我将一个列表
  • 如何使用 maven- assembly-plugin 版本 3 设置最终的 jar 名称

    在旧版本的插件中 您可以使用
  • 无法声明接口:资源繁忙

    我正在使用 USB4Java 低级版本 并且基本上是根据这段代码工作的here http www mets blog com java usb communication usb4java 我在 Ubuntu 中工作 遇到了有关权限的问题
  • Angular2 中的 MVW 代表什么?

    我有很多介绍 MVC MVP MVVM 等的链接 但我没有得到一个可以说明 M 在 Angular2 中到底代表什么 V 在 Angular2 中到底代表什么以及 W 在 Angular2 中到底代表什么的信息 也许W有一个答案 那就是W代
  • 将表与同一个表的前一条记录连接起来

    我有一个包含历史记录的表 由主表中的多个触发器发布到那里 我想在历史表上创建一个 select 语句 其中每个记录都由其先前的记录 由相同的 LineID 和最高的 ActionDate 标识 连接 这样我就可以提取这两者之间的差异 我尝试
  • 我可以更改 LongListMultiSelector 中的复选框颜色吗? WP8

    我需要更改 Windows Phone 8 中 LongListMultiSelector 复选框的颜色 因为我的背景是白色 这可能吗 Thanks 为此 您必须首先通过在 Visual Studio 中的文档大纲中右键单击长列表选择器来编
  • 国家/地区的下拉菜单

    您好 我想为国家和州实现下拉菜单 州下拉列表应根据所选国家 地区更改其值 有没有任何插件或 gem 可以在 Rails 中执行此操作 尝试卡门插件 http autonomousmachine com posts 2009 4 1 carm

随机推荐

  • react+antd出现preventDefault()警告报错

    react项目遇到如下报错 This synthetic event is reused for performance reasons If you re seeing this you re accessing the method p
  • 【C++】类和对象-多态

    1 多态的基本语法 代码 include
  • 【微信小程序】小程序长按复制文本

    微信小程序的文本 要具有长按复制功能 必须满足两个条件 文本在
  • Python类、模块、包

    http www cppblog com len archive 2008 07 24 57078 html Python在处理功能复用和功能颗粒度划分时采用了类 模块 包的结构 这种处理跟C 中的类和名字空间类似 但更接近于Java所采用
  • linux开发板通过网线连接电脑(win10)连接网络问题

    最近开始学习嵌入式Linux开发 使用野火imx6ull开发板 想把开发板通过网线连接到笔记本 笔记本连接WiFi 共享使用网络 查询了很多资料后成功实现 我现在把这个方法分享出来 1 禁用防火墙功能 打开网络和共享中心 gt window
  • .net dapper简单使用

    以本地mysql数据库为例 准备工作 新建数据库 新建表 例如book表 然后定义Book类 book表和Book类应对应 这样dapper才能把他们映射好 在appsettings json中配置数据库连接 ConnectionStrin
  • pytorch autograd计算标量函数二阶导数

    计算标量函数 y x 3 s i n
  • 微信公众号实现简易的物联网控制(一)

    这篇主要说说如何通过微信公众号来查看室内传感器数据 至于硬件部分和物联网平台以后再详细说明 准备工作 1 申请微信公众号 2 搭建云服务器 首先说明一下整体流程 用户发送相应的指令到公众号后台 服务器根据指令的内容调用OneNET的API获
  • 深入理解JVM(四)JVM的垃圾回收机制

    文章目录 1 什么是垃圾回收机制 2 Java中的引用类型 3 如何判断对象是否可以被回收 4 方法区的垃圾收集 5 垃圾收集算法 5 1 标记 清除 Mark Sweep 算法 5 2 标记整理 Mark Compact 算法 5 3 复
  • 谭浩强C++课后习题16——矩阵对角线元素之和

    谭浩强C 课后习题16 矩阵对角线元素之和 题目描述 求一个n n矩阵对角线元素之和 算法思路 定义一个动态二维数组 定义方法 定义一个指向指针的指针 令其指向每一行的首地址 循环n次 定义n个一维数组 循环n次 对角线之和即为每一行num
  • Dynamics 365发送邮件

    在Dynamics 365 CRM 开发中 发送邮件除了CRM自带的邮件以外 还可以使用代码发送邮件 大大丰富了邮件的内容 满足客户不同的需求 Entity email new Entity email 邮件接收人 类型为 EntityCo
  • 梳理总结线程池知识(内含常用线程池选型技巧及其API分类讲解)

    核心 救急线程概念 核心线程 救急线程 二者区别 原始线程池的构造方法 常用线程池及其适用场景 FixedThreadPool CachedThreadPool SingleThreadExecutor ScheduledExecutor
  • Opecncv-python使用踩坑篇(一)

    import cv2时 RuntimeError module compiled against API version 0xb but this version of numpy is 0xaTraceback most recent c
  • 【Proteus仿真】DAC0832+51单片机汇编实现三角波输出

    Proteus仿真 DAC0832 51单片机汇编实现三角波输出 Proteus仿真 汇编代码 asm 利用DAC0832产生三角波 程序如下 本程序中产生的电压的最大幅度受DAC0832的基准电压限制 产生的的三角波周期受累加器A的控制
  • 噪声库NOISEX-92下载并用python转为wav

    0 直接一键获取 可以进我的CSDN下载 https download csdn net download weixin 44908427 85833708 也可以留言发邮箱 1 数据下载 官方下载链接 NOISEX 92 下载下来后是ma
  • Python本地安装的包(setup.py / pip install -e)复制后需要重新安装

    之前运行的AE代码 然后为了改charnet复制了一份 然后就发现在新复制的目录里面程序打断点也会跳过 而且在aetextspotter py里面增加一些输出也没变化 这是因为aetextspotter py所在的目录mmdet是通过pyt
  • IT项目管理作业八

    RUNNING CASE 第一题 90 的员工在系统推出后的两周内登录了该系统 90 的员工在系统推出后的四周内完成了有关该系统的培训 该系统帮助确定了25 的员工如何改善健康状况 25 的员工已将改善健康的目标纳入系统 并通过报名参加项目
  • C#和Java之间的语法和特性差异

    C 和Java是两种常见的面向对象编程语言 虽然它们在许多方面都非常相似 但仍然有一些不同之处 下面是它们之间的主要差异以及相应的功能列表 语法差异 C 使用分号作为语句结束符 而Java使用分号和花括号 C 使用 using 关键字导入命
  • Codeforces Round #776 (Div. 3)

    菜鸡在这里做做笔记 各位进来的大佬我先 orz 了 B include
  • App的启动过程(10)surfaceflinger对数据合成,送显

    下面就是SurfaceFlinger执行实际的数据合成 然后刷新到屏幕上 voidSurfaceFlinger onMessageReceived int32 t what switch what case MessageQueue INV