<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Android 圖形架構(gòu)之一 ——概述

          共 5049字,需瀏覽 11分鐘

           ·

          2022-07-11 13:16

          本系列的文章,可以讓你明白,一個(gè)View最終是如何顯示到屏幕上的,從應(yīng)用層到硬件抽象層。對(duì)分析app的卡頓,掉幀等 有很大幫助。

          App 的繪圖方式

          應(yīng)用層可通過(guò)兩種方式將圖像繪制到屏幕上:使用 Canvas 或 OpenGL :

          • android.graphics.Canvas 是一個(gè) 2D 圖形 API , Canvas API 通過(guò)一個(gè)名為 OpenGLRenderer 的繪制庫(kù)實(shí)現(xiàn)硬件加速,該繪制庫(kù)將 Canvas 運(yùn)算轉(zhuǎn)換為 OpenGL 運(yùn)算,以便它們可以在 GPU 上執(zhí)行。從 Android 4.0 開(kāi)始,硬件加速的 Canvas 默認(rèn)情況下處于啟用狀態(tài)

          • 使用 OpenGL ES 直接渲染到 Surface 。Android 在 Android.opengl 軟件包中提供了 OpenGL ES 接口

          下面這張官方圖片,提現(xiàn)了 圖像流 從 Image stream producers 到Surface,再被 Image stream consumers 中的SurfaceFlinger(其中也有OpenGl ES的一些工作)消費(fèi)掉,再到硬件抽象層,最后顯示到屏幕上

          Activity 也是需要?jiǎng)?chuàng)建Surface的, Activity顯示流程為:

          1. startActivity啟動(dòng)Activity;

          2. 為Activity創(chuàng)建一個(gè)window(PhoneWindow),并在WindowManagerService中注冊(cè)這個(gè)window;

          3. WindowManagerService會(huì)要求SurfaceFlinger為這個(gè)window創(chuàng)建一個(gè)surface用來(lái)繪圖。SurfaceFlinger創(chuàng)建一個(gè)Surface。(在SurfaceFlinger中Surface 是用Layer來(lái)體現(xiàn)的,也就是說(shuō)App中的一個(gè)Surface ,對(duì)應(yīng)SurfaceFlinger的一個(gè)Layer),這個(gè)layer的核心即是一個(gè)BufferQueue(),這時(shí)候app就可以在這個(gè)layer上render了;

          4. 將所有的layer進(jìn)行合成,顯示到屏幕上。

          一般app而言,屏幕會(huì)有三個(gè)layer:屏幕頂端的status bar,屏幕下面的navigation bar,還有就是app的UI部分。

          app的layer可能多余或者少于3個(gè),例如對(duì)全屏顯示的app就沒(méi)有status bar。

          status bar和navigation bar是由系統(tǒng)進(jìn)行去render。而app的UI部分對(duì)應(yīng)的layer 是由它自己去處理(通知SurfaceFlinger處理),最后需要把這些layer合成 。

          Surface和SurfaceFlinger

          無(wú)論開(kāi)發(fā)者使用Canvas 或 OpenGLI,一切內(nèi)容都會(huì)渲染到 Surface 。在 Android 平臺(tái)上創(chuàng)建的每個(gè)窗口都由 Surface 提供支持。

          SurfaceFlinger 會(huì)把系統(tǒng)中所有應(yīng)用程序的最終的“繪圖結(jié)果”進(jìn)行“混合”,然后統(tǒng)一顯示到物理屏幕上,

          GraphicBuffer、BufferQueue


          圖像流生產(chǎn)者與圖像流消費(fèi)者 的數(shù)據(jù)傳遞就是通過(guò) BufferQueue ,里面有很多的GraphicBuffer

          這是生產(chǎn)者消費(fèi)者模型。一旦生產(chǎn)者 有新數(shù)據(jù),就會(huì)通知 SurfaceFlinger 進(jìn)行消費(fèi),最后顯示到屏幕

          生產(chǎn)者和消費(fèi)者可能是在不同的進(jìn)程,它們的通信不是用Binder,為了高效傳輸大塊數(shù)據(jù),使用匿名共享內(nèi)存,BufferQueue 不會(huì)復(fù)制緩沖區(qū)內(nèi)容;通過(guò)句柄進(jìn)行傳遞。

          下圖是上圖的細(xì)化

          接下來(lái)具體說(shuō)明客戶(hù)端(producer)和服務(wù)端SurfaceFlinger(consumer)工作的模式:首先這里的buffer是共享緩沖區(qū),故肯定會(huì)涉及到互斥鎖,所以buffer的狀態(tài)也會(huì)有多種,一般的buffer大致會(huì)經(jīng)過(guò)FREE->DEQUEUED->QUEUED->ACQUIRED->FREE這個(gè)流程,如下圖:

          • BufferQueue:Producer向BufferQueue中寫(xiě)數(shù)據(jù),Consumer從BufferQueue中讀數(shù)據(jù)。

          • Producer:生產(chǎn)者。因?yàn)閼?yīng)用程序不斷地刷新UI,從而將產(chǎn)生的顯示數(shù)據(jù)源源不斷地寫(xiě)到BufferQueue:Producer中。當(dāng)Producer需要使用一塊buffer時(shí),調(diào)用BufferQueue的dequeue函數(shù),獲得的buffer就只屬于producer,當(dāng)生產(chǎn)者認(rèn)為一塊buffer已經(jīng)寫(xiě)入完成后,調(diào)用BufferQueue的queue函數(shù),把buffer歸還到BufferQueue的隊(duì)列中。

          • Consumer:消費(fèi)者 。當(dāng)生產(chǎn)者準(zhǔn)備好數(shù)據(jù)后,BufferQueue就會(huì)調(diào)用onFrameAvailable()來(lái)通知Consumer進(jìn)行消費(fèi)

          圖像生產(chǎn)者 例如:相機(jī) HAL 或 OpenGL ES 游戲生成的相機(jī)預(yù)覽。

          圖像消費(fèi)者 例如:SurfaceFlinger 或顯示 OpenGL ES 流的另一個(gè)應(yīng)用,如顯示相機(jī)取景器的相機(jī)應(yīng)用。

          BufferQueue 通常用于渲染到 Surface ,并且與 GL 消費(fèi)者及其他任務(wù)一起消耗內(nèi)容。BufferQueue 可以在三種不同的模式下運(yùn)行:

          • 類(lèi)同步模式 默認(rèn)情況下, BufferQueue 在類(lèi)同步模式下運(yùn)行,在該模式下,從生產(chǎn)者進(jìn)入的每個(gè)緩沖區(qū)都在消費(fèi)者那退出。在此模式下不會(huì)舍棄任何緩沖區(qū)。如果生產(chǎn)者速度太快,創(chuàng)建緩沖區(qū)的速度比消耗緩沖區(qū)的速度更快,它將阻塞并等待可用的緩沖區(qū)。

          • 非阻塞模式 BufferQueue 還可以在非阻塞模式下運(yùn)行,在此類(lèi)情況下,它會(huì)生成錯(cuò)誤,而不是等待緩沖區(qū)。在此模式下也不會(huì)舍棄緩沖區(qū)。這有助于避免可能不了解圖形框架的復(fù)雜依賴(lài)項(xiàng)的應(yīng)用軟件出現(xiàn)潛在死鎖現(xiàn)象。

          • 舍棄模式 BufferQueue 可以配置為丟棄舊緩沖區(qū),而不是生成錯(cuò)誤或進(jìn)行等待。例如,如果對(duì)紋理視圖執(zhí)行 GL 渲染并盡快繪制,則必須丟棄緩沖區(qū)。

          EGL OpenGL

          Android 平臺(tái)圖形處理 API 的標(biāo)準(zhǔn):

          • OpenGL 是由 SGI 公司開(kāi)發(fā)的一套 3D 圖形軟件接口標(biāo)準(zhǔn),由于具有體系結(jié)構(gòu)簡(jiǎn)單合理、使用方便、與操作平臺(tái)無(wú)關(guān)等優(yōu)點(diǎn), OpenGL 迅速成為 3D 圖形接口的工業(yè)標(biāo)準(zhǔn),并陸續(xù)在各種平臺(tái)上得以實(shí)現(xiàn)。

          • OpenGL ES 是由 khronos 組織根據(jù)手持及移動(dòng)平臺(tái)的特點(diǎn),對(duì) OpenGL 3D 圖形 API 標(biāo)準(zhǔn)進(jìn)行裁剪定制而形成的。

          • Vulkan 是由 khronos 組織在 2016 年正式發(fā)布的,是 OpenGL ES 的繼任者。API 是輕量級(jí)、更貼近底層硬件 close-to-the-metal 的接口,可使 GPU 驅(qū)動(dòng)軟件運(yùn)用多核與多線程 CPU 性能。

          OpenGL ES 是 Android 繪圖 API ,但 OpenGL ES 是平臺(tái)通用的,與系統(tǒng)無(wú)關(guān)的,在特定設(shè)備上使用需要一個(gè)中間層做適配, Android 中這個(gè)中間層就是 EGL 。

          FrameBuffer

          Linux 抽象出 FrameBuffer 這個(gè)設(shè)備來(lái)供用戶(hù)態(tài)進(jìn)程實(shí)現(xiàn)直接寫(xiě)屏。FrameBuffer 機(jī)制模仿顯卡的功能,是顯卡硬件的抽象,可以通過(guò) FrameBuffer 的讀寫(xiě)直接對(duì)顯存進(jìn)行操作。

          用戶(hù)可以將 FrameBuffer 看成是顯示內(nèi)存的一個(gè)映像,將其映射到進(jìn)程地址空間之后,就可以直接進(jìn)行讀寫(xiě)操作,而寫(xiě)操作可以立即反應(yīng)在屏幕上。

          用戶(hù)不必關(guān)心物理顯存的位置、換頁(yè)機(jī)制等等具體細(xì)節(jié),這些都是由 FrameBuffer 設(shè)備驅(qū)動(dòng)來(lái)完成的。但 FrameBuffer 本身不具備任何運(yùn)算數(shù)據(jù)的能力。 

          CPU 將運(yùn)算后的結(jié)果放到FrameBuffer,就會(huì)顯示處理,中間不會(huì)對(duì)數(shù)據(jù)做處理。應(yīng)用程序也可以直接讀寫(xiě)FrameBuffer,盡管 FrameBuffer 需要真正的顯卡驅(qū)動(dòng)的支持,但所有顯示任務(wù)都有 CPU 完成,因此 CPU 負(fù)擔(dān)很重。

          幀緩存可以在系統(tǒng)存儲(chǔ)器(內(nèi)存)的任意位置,視頻控制器通過(guò)訪問(wèn)幀緩存來(lái)刷新屏幕。

          幀緩存也叫刷新緩存 FrameBuffer 或 RefreshBuffer ,這里的幀 Frame 是指整個(gè)屏幕范圍。幀緩存有個(gè)地址,是在內(nèi)存里。我們通過(guò)不停的向 FrameBuffer 中寫(xiě)入數(shù)據(jù),顯示控制器就自動(dòng)的從 FrameBuffer 中取數(shù)據(jù)并顯示出來(lái)。全部的圖形都共享內(nèi)存中同一個(gè)幀緩存。

          FrameBuffer 幀緩沖實(shí)際上包括兩個(gè)不同的方面:

          • Frame :幀,就是指一幅圖像,在屏幕上看到的那幅圖像就是一幀
          • Buffer :緩沖,就是一段存儲(chǔ)區(qū)域,可這個(gè)區(qū)域存儲(chǔ)的是幀

          FrameBuffer 就是一個(gè)存儲(chǔ)圖形/圖像幀數(shù)據(jù)的緩沖。Linux 內(nèi)核提供了統(tǒng)一的 Framebuffer 顯示驅(qū)動(dòng),設(shè)備節(jié)點(diǎn) /dev/graphics/fb* 或者 /dev/fb* ,以 fb0 表示第一個(gè) Monitor ,這個(gè)虛擬設(shè)備將不同硬件廠商實(shí)現(xiàn)的真實(shí)設(shè)備統(tǒng)一在一個(gè)框架下,這樣應(yīng)用層就可以通過(guò)標(biāo)準(zhǔn)的接口進(jìn)行圖形/圖像的輸入和輸出了:

          Gralloc

          Gralloc 的含義為是 Graphics Alloc 圖形分配 。Android 系統(tǒng)在硬件抽象層中提供了一個(gè) Gralloc 模塊,封裝了對(duì) Framebuffer 的所有訪問(wèn)操作。

          Gralloc 模塊符合 Android 標(biāo)準(zhǔn)的 HAL 架構(gòu)設(shè)計(jì);它分為 fb 和 gralloc 兩個(gè)設(shè)備:前者負(fù)責(zé)打開(kāi)內(nèi)核中的 Framebuffer 、初始化配置,以及提供 post, setSwapInterval 等操作;后者則管理幀緩沖區(qū)的分配和釋放。上層只能通過(guò) Gralloc 訪問(wèn)幀緩沖區(qū),這樣一來(lái)就實(shí)現(xiàn)了有序的封裝保護(hù)。

          Gralloc 分配器返回的句柄可以通過(guò) Binder 在進(jìn)程之間傳遞。

          Hardware Composer

          HWC(hwcomposer)是Android中進(jìn)行窗口(Layer)合成和顯示的HAL層模塊,其實(shí)現(xiàn)是特定于設(shè)備的,而且通常由顯示設(shè)備制造商 (OEM)完成,為SurfaceFlinger服務(wù)提供硬件支持。

          SurfaceFlinger可以使用OpenGL ES合成Layer,這需要占用并消耗GPU資源。

          大多數(shù)GPU都沒(méi)有針對(duì)圖層合成進(jìn)行優(yōu)化,當(dāng)SurfaceFlinger通過(guò)GPU合成圖層時(shí),應(yīng)用程序無(wú)法使用GPU進(jìn)行自己的渲染。而HWC通過(guò)硬件設(shè)備進(jìn)行圖層合成,可以減輕GPU的合成壓力。

          顯示設(shè)備的能力千差萬(wàn)別,很難直接用API表示硬件設(shè)備支持合成的Layer數(shù)量,Layer是否可以進(jìn)行旋轉(zhuǎn)和混合模式操作,以及對(duì)圖層定位和硬件合成的限制等。因此HWC描述上述信息的流程是這樣的:

          1. SurfaceFlinger向HWC提供所有Layer的完整列表,讓HWC根據(jù)其硬件能力,決定如何處理這些Layer。
          2. HWC會(huì)為每個(gè)Layer標(biāo)注合成方式,是通過(guò)GPU還是通過(guò)HWC合成。
          3. SurfaceFlinger負(fù)責(zé)先把所有注明GPU合成的Layer合成到一個(gè)輸出Buffer,然后把這個(gè)輸出Buffer和其他Layer(注明HWC合成的Layer)一起交給HWC,讓HWC完成剩余Layer的合成和顯示。

          至此,本系列涉及到的內(nèi)容主要內(nèi)容,都大概描述了一下,還有一些流程中涉及到的VSync,WMS等,這些不是很影響整體的邏輯,再后面的文章再具體分析。

          原文地址:https://xuexuan.blog.csdn.net/article/details/108870372

          最后歡迎大家加入 音視頻開(kāi)發(fā)進(jìn)階 知識(shí)星球 ,這里有知識(shí)干貨、編程答疑、開(kāi)發(fā)教程,還有很多精彩分享。


          更多內(nèi)容可以在星球菜單中找到,隨著時(shí)間推移,干貨也會(huì)越來(lái)越多!!!


          給出 10元 優(yōu)惠券,漲價(jià)在即,目前還是白菜價(jià),基本上提幾個(gè)問(wèn)題就回本,投資自己就是最好的投資!!!


          加我微信 ezglumes ,拉你進(jìn)技術(shù)交流群

          推薦閱讀:

          音視頻開(kāi)發(fā)工作經(jīng)驗(yàn)分享 || 視頻版

          OpenGL ES 學(xué)習(xí)資源分享

          開(kāi)通專(zhuān)輯 | 細(xì)數(shù)那些年寫(xiě)過(guò)的技術(shù)文章專(zhuān)輯

          Android NDK 免費(fèi)視頻在線學(xué)習(xí)!!!

          你想要的音視頻開(kāi)發(fā)資料庫(kù)來(lái)了

          推薦幾個(gè)堪稱(chēng)教科書(shū)級(jí)別的 Android 音視頻入門(mén)項(xiàng)目

          覺(jué)得不錯(cuò),點(diǎn)個(gè)在看唄~


          瀏覽 188
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  www.青春草 | 91探花视频在线观看 | 蜜桃亚洲无码电影 | 爽爽综合网 | 操逼视频在线观看视频 |