当前位置: 首页 > news >正文

Android显示学习笔记本

根据博客 Android-View 绘制原理(01)-JAVA层分析_android view draw原理分析-CSDN博客

提出了我的疑问  Canvas RenderNode updateDisplayListDirty 这些东西的关系

您的理解在基本方向上是对的,但让我详细解释一下 Android 中 updateDisplayListDirty、指令集合、Canvas 和 RenderNode 之间的关系:

RenderNode 与渲染过程

在 Android 的渲染系统中:

  1. RenderNode
    • 是一个存储渲染操作的容器
    • 包含了视图的绘制命令和属性信息
    • 可以被缓存和重用,提高渲染效率
  2. DisplayList
    • 实际上是 RenderNode 内部的绘制命令列表
    • 存储了一系列需要执行的渲染指令
    • 通过 updateDisplayListDirty 方法更新这些指令
  3. Canvas
    • 是应用层与渲染系统交互的接口
    • 提供了各种绘制方法(drawRect、drawText 等)
    • 当我们调用 Canvas 的绘制方法时,它会转换为渲染指令

updateDisplayListDirty 与 Canvas 的关系

updateDisplayListDirty 方法在 View 类中实现,主要作用是:

  1. 创建或获取一个 RenderNode
  2. 使用 DisplayListCanvas(特殊的 Canvas 实现)录制绘制指令
  3. 当视图调用 onDraw() 方法时,它使用提供的 Canvas 执行绘制
  4. 这些绘制命令被记录到 DisplayList 中
  5. 最终生成或更新 RenderNode

Canvas 和 DisplayList 不是可替代关系,而是协作关系:

  • Canvas 是绘制接口,应用通过它表达"画什么"
  • DisplayList 是指令集合,记录"如何画"
  • RenderNode 是整个结构的容器,包含了 DisplayList 和其他渲染属性

所以不是"有一个就可以了",而是它们在渲染管线中扮演不同角色:Canvas 是应用用来绘制的工具,而 DisplayList 是记录这些绘制指令的容器,两者共同构成了 Android 的高效渲染系统。

 看完后我的疑问变成了,既然 updateDisplayListDirty  是一个指令集合 在硬件加速的情况下,一个渲染当VSYNC信号来了,进行三大流程进行获取surfaceControl然后进行 绘制,绘制时候先新建RenderNode 然后获取 RenderNode 的 

RecordingCanvas canvas = mRootNode.beginRecording(mSurfaceWidth, mSurfaceHeight);
RecordingCanvas 然后把它变成后续的 Canvas
最后  

   public void endRecording() {if (mCurrentRecordingCanvas == null) {throw new IllegalStateException("No recording in progress, forgot to call #beginRecording()?");}RecordingCanvas canvas = mCurrentRecordingCanvas;mCurrentRecordingCanvas = null;canvas.finishRecording(this);canvas.recycle();}

finishRecording 把 当前的 RenderNode 传过去 然后进行绘制

那么我的问题是 之后surfaceFlinger是否绘制的是指令集合?是否是当RecordingCanvas  执行一次生成一个指令就绘制一部分还是 finishRecording 后一起进行绘制?

您的问题涉及到 Android 渲染流水线的关键细节,我来详细解释:

finishRecording 与渲染流程

在 Android 的硬件加速渲染流程中,当 finishRecording() 被调用时:

  1. 指令集完成阶段
    • finishRecording() 标志着 RecordingCanvas 已经完成所有绘制命令的记录
    • 此时,所有来自 onDraw() 的绘制操作已经被转换为渲染指令并存储在 RenderNode 中
    • 这些指令并不会立即触发绘制
  2. 批处理渲染模式
    • SurfaceFlinger 不会 在每条指令生成后立即渲染
    • 系统采用批处理模式,收集完所有指令后一次性处理
    • 这种方式大大提高了渲染效率,避免了频繁的状态切换和上下文切换
  3. 渲染时机
    • ViewRootImpl.performTraversals() 完成后,会调用 ThreadedRenderer.draw()
    • 此时,所有视图的 RenderNode 都已准备就绪
    • 系统会将这些渲染命令通过 HWUI 传递给 GPU
    • SurfaceFlinger 会在下一个 VSYNC 信号到来时合成并显示结果
  4. SurfaceFlinger 处理
    • SurfaceFlinger 接收的是已经处理过的图层数据
    • 它主要负责合成多个应用的图层,而不是执行具体的绘制指令
    • 实际的指令执行发生在 GPU 上,在应用进程的渲染线程中

所以,回答您的核心问题:系统是在 finishRecording() 后,将完整的指令集合一次性提交给渲染管线进行处理,而不是每生成一条指令就执行一次渲染。这种批处理模式是现代图形渲染系统的普遍做法,可以最大限度地减少 GPU 状态切换,提高渲染效率。

需要注意的是,RecordingCanvas 记录的指令集和 SurfaceFlinger 处理的内容在概念上有区别——前者是应用内的绘制指令,后者处理的是已经渲染好的图层。

 

那这些指令在哪被处理?

这些渲染指令的处理发生在多个层次的渲染管线中,让我详细解释这个流程:

渲染指令的处理路径

  1. 应用进程中的处理
    • finishRecording() 完成后,渲染指令首先在应用自己的渲染线程中处理
    • ThreadedRenderer 类负责协调这个过程
    • 具体处理由 HWUI (Hardware User Interface) 库在原生层完成
    • 在这一阶段,渲染指令被转换为 GPU 可以理解的命令(如 OpenGL ES 或 Vulkan 调用)
  2. RenderThread 中的执行
    • Android 使用专门的 RenderThread(渲染线程)处理这些指令
    • 这个线程与主线程分离,可以并行处理渲染工作
    • 渲染指令在这里被组织成命令缓冲区(Command Buffer)
    • 这些命令最终会通过图形驱动提交给 GPU
  3. GPU 执行阶段
    • GPU 接收这些渲染命令并执行实际的像素处理
    • 渲染结果被写入到应用的 Surface 对应的图形缓冲区中
    • 这个过程完全由 GPU 硬件加速完成
  4. SurfaceFlinger 的角色
    • SurfaceFlinger 不处理原始渲染指令,而是处理已渲染好的图层
    • 它从各个应用获取已经渲染好的图形缓冲区
    • 然后进行合成(Composition)操作,决定不同应用的图层如何叠加显示
    • 最后将合成结果提交给显示硬件

具体源码路径

如果您想在源码中追踪这个处理过程:

  1. ThreadedRenderer.nSyncAndDrawFrame() 是关键的入口点,它通过 JNI 调用原生层代码
  2. 在原生层,android_view_ThreadedRenderer.cpp 包含了相关实现
  3. 进一步深入到 libs/hwui/ 目录,特别是 RenderProxyRenderThread 相关类
  4. 最终的 GPU 命令提交通过图形驱动 API(如 OpenGL ES 或 Vulkan)完成

所以,渲染指令主要在应用自己的渲染线程中被处理和执行,而不是在 SurfaceFlinger 中。SurfaceFlinger 的工作是在所有应用都完成各自的渲染后,组合这些结果并显示到屏幕上。

相关文章:

  • 第一天 车联网定义、发展历程与生态体系
  • 机器学习中的标签策略:直接标签、代理标签与人工数据生成
  • 清华大学正式成立人工智能医院
  • 北重数控滑台加工厂家:汽车零部件试验铁地板-安全性能的测试方法
  • 代码片段存储解决方案ByteStash
  • 八大排序——直接插入排序/希尔排序
  • python使用dlib的5点和68点的人脸检测
  • 深入理解缓存淘汰策略:LRU 与 LFU 算法详解及 Java 实现
  • springboot 实现敏感信息脱敏
  • OpenCV 图形API(69)图像与通道拼接函数------将一个 GMat 类型的对象转换为另一个具有不同深度GMat对象函数convertTo()
  • git 修改用户名和邮箱
  • 关于常量指针和指向常量的指针
  • HTML5好看的水果蔬菜在线商城网站源码系列模板7
  • vue复习91~135
  • GPU 架构入门笔记
  • 获得ecovadis徽章资格标准是什么?ecovadis评估失败的风险
  • 【ACL系列论文写作指北07-论文标题与关键词部分怎么写】-赢在第一眼
  • 今日行情明日机会——20250428
  • leetcode128-最长连续序列
  • 【默子AI】万字长文:MCP与A2A协议详解
  • 2025上海车展 | 当智驾不再让人兴奋,汽车智能化暗战升级
  • 上海出台灵活就业人员公积金新政:不限户籍、提取自由,6月起施行
  • 哈马斯同意释放剩余所有以方被扣押人员,以换取停火五年
  • 新版国家卫生监督抽查计划发布,首次明确打击网络“医托”
  • 四川甘孜州白玉县发生4.9级地震,震源深度10千米
  • 阿联酋启动第三届全球航空奖评选,奖金总额达百万美元