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 的工作是在所有應用都完成各自的渲染后,組合這些結果并顯示到屏幕上。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/78548.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/78548.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/78548.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JavaWeb學習打卡-Day4-會話技術、JWT、Filter、Interceptor

會話技術 會話:用戶打開瀏覽器,訪問web服務器的資源,會話建立,直到有一方斷開連接,會話結束。在一次會話中可以包含多次請求和響應。會話跟蹤:一種維護瀏覽器狀態的方法,服務器需要識別多次請求…

讓數據優雅落地:用 serde::Deserialize 玩轉結構體實體

前言 想象一下,服務器突然飛來一堆 JSON 數據,就像一群無頭蒼蠅沖進辦公室,嗡嗡作響,橫沖直撞。此刻,你的任務,就是把這群“迷路數據”安置進正確的格子里,分門別類,秩序井然,不混不亂,不漏一只。 好在 Rust 早就為我們備好瑞士軍刀:serde::Deserialize。它不僅刀…

Virtio 技術解析 | 框架、設備實現與實踐指南

本文為 “Virtio” 相關文章合輯。 略作重排,如有內容異常,請看原文。 Virtio 簡介(一)—— 框架分析 posted 2021-04-21 10:14 Edver 1. 概述 在傳統設備模擬中,虛擬機內部設備驅動完全不知自身處于虛擬化環境&a…

云計算賦能質檢LIMS的價值 質檢LIMS系統在云計算企業的創新應用

在云計算技術高速發展的背景下,實驗室信息化管理正經歷深刻變革。質檢LIMS(實驗室信息管理系統)作為實驗室數字化轉型的核心工具,通過與云計算深度融合,為企業提供了高彈性、高安全性的解決方案。本文將探討質檢LIMS在…

【win11 安裝WSL2 詳解一遍過!!】

共有五個步驟,按部就班的做,保準成功! 1. 打開開發者模式 設置->系統->開發者模式 2. 打開linux的win子系統 找到控制面板-程序和功能-啟用或關閉Windows功能,選中“適用于Linux的Windows子系統”,“虛擬機…

Godot開發2D冒險游戲——第三節:游戲地圖繪制

一、初步構建游戲地圖 在游戲場景當中添加一個新的子節點:TileMapLayer 這一層稱為瓦片地圖層 根據提示,下一步顯然是添加資源 為TileMapLayer節點添加一個TileSet 將地板添加進來,然后選擇自動分割圖集 自定義時要確保大小合適 讓Godot自…

Django創建的應用目錄詳細解釋以及如何操作數據庫自動創建表

創建好Django項目后 如果要創建 python manage.py startapp 模塊名模塊 使用 我創建一個system模塊后是 注意:urls是我自己建的文件 1.migrations目錄 存放數據庫的遷移文件,當models.py中模型定義發生變化時,通過遷移操作能同步數據庫結構變化 __init__ 使該目錄…

將輸入幀上下文打包到下一個幀的預測模型中用于視頻生成

Paper Title: Packing Input Frame Context in Next-Frame Prediction Models for Video Generation 論文發布于2025年4月17日 Abstract部分 在這篇論文中,FramePack是一種新提出的網絡結構,旨在解決視頻生成中的兩個主要問題:遺忘和漂移。 具體來說,遺忘指的是在生成視…

STM32 串口USART

目錄 常見的通信方式 串行通信和并行通信 全雙工,半雙工和單工通信 同步通信和異步通信 通信速率 常見的通信協議 串口基礎知識 電平特性 串口傳輸協議 STM32F103的USART資源 端口引腳 數據寄存器單元 發送接收控制單元 實現串口發送 printf…

Taro on Harmony :助力業務高效開發純血鴻蒙應用

背景 純血鴻蒙逐漸成為全球第三大操作系統,業界也掀起了適配鴻蒙原生的浪潮,用戶遷移趨勢明顯,京東作為國民應用,為鴻蒙用戶提供完整的購物體驗至關重要。   去年 9 月,京東 AP…

gem5-gpu教程05 內存建模

memory-modeling|Details on how memory is modeled in gem5-gpu gem5-gpu’s Memory Simulation gem5-gpu在很大程度上避開了GPGPU-Sim的單獨功能模擬,而是使用了gem5的執行中執行模型。因此,當執行存儲/加載時,內存會被更新/讀取。沒有單獨的功能路徑。(順便說一句,這…

【python】lambda用法(結合例子理解)

目錄 lambda 是什么? 為什么叫 lambda? 語法 舉例 1. 最簡單的 lambda:單個數字處理 2. 用 lambda 排序一組字符串(按照長度排序) 3. 在列表里找出絕對值最小的數字 4. 給 map() 用 lambda 5. 組合使用:篩選出偶數 lambda 和 def 的對比 lambda 適合用在什么地…

【ROS2】機器人操作系統安裝到Ubuntu22.04簡介(手動)

主要參考: https://book.guyuehome.com/ROS2/1.系統架構/1.3_ROS2安裝方法/ 官方文檔:https://docs.ros.org/en/humble/Installation.html 虛擬機與ubuntu系統安裝 略,見參考文檔 ubutun換國內源,略 1. 設置本地語言 確保您有…

C 調用 C++:extern “C” 接口詳解與實踐 C/C++混合編譯

C 調用 C:extern “C” 接口詳解與實踐 核心問題在于 C 編譯器會對函數名進行“修飾”(Name Mangling)以支持函數重載等特性,而 C 編譯器則不會。此外,C 語言本身沒有類、對象等概念。為了解決這個問題,我…

汽車制造行業如何在數字化轉型中抓住機遇?

近年來,隨著新一輪科技革命和產業變革的深入推進,汽車制造行業正迎來一場前所未有的數字化轉型浪潮。無論是傳統車企還是新勢力品牌,都在積極探索如何通過數字化技術提升競爭力、開拓新市場。那么,在這場變革中,汽車制…

k8s學習記錄(五):Pod親和性詳解

一、前言 上一篇文章初步探討了 Kubernetes 的節點親和性,了解到它在 Pod 調度上比傳統方式更靈活高效。今天我們繼續討論親和性同時Kubernetes 的調度機制。 二、Pod親和性 上一篇文章中我們介紹了節點親和性,今天我們講解一下Pod親和性。首先我們先看…

HarmonyOS:Navigation實現導航之頁面設置和路由操作

導讀 設置標題欄模式設置菜單欄設置工具欄路由操作頁面跳轉頁面返回頁面替換頁面刪除移動頁面參數獲取路由攔截 子頁面頁面顯示類型頁面生命周期頁面監聽和查詢 頁面轉場關閉轉場自定義轉場共享元素轉場 跨包動態路由系統路由表自定義路由表 示例代碼 Navigation組件適用于模塊…

雪花算法

目錄 一、什么是雪花算法 二、使用雪花算法 ?三、使用UUID 使用自增主鍵是數據庫中常用的唯一標識,今天嘗試使用mybatisplus來實現三種方式的主鍵ID 使用起來也很簡單 用注解指定一下使用那種方式的主鍵 一、什么是雪花算法 一種特殊的算法可以計算得到一個唯…

HarmonyOs @hadss/hmrouter路由接入

參考文檔:官方文檔 在根目錄oh-package.json5配置 {"dependencies": {"hadss/hmrouter": "^1.0.0-rc.11"} }加入路由編譯插件 hvigor/hvigor-config.json文件 {"dependencies": {"hadss/hmrouter-plugin": &…

C++學習筆記(三十八)——STL之修改算法

STL 算法分類: 類別常見算法作用排序sort、stable_sort、partial_sort、nth_element等排序搜索find、find_if、count、count_if、binary_search等查找元素修改copy、replace、replace_if、swap、fill等修改容器內容刪除remove、remove_if、unique等刪除元素歸約for…