<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                1. 顯示層(Layer)和屏幕組成 你了解屏幕顯示的漂亮界面是如何組織的嗎?來看圖8-10所展示的屏幕組成示意圖: :-: ![](http://img.blog.csdn.net/20150802162331307?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-10 屏幕組成示意圖 從圖8-10中可以看出: - 屏幕位于一個三維坐標系中,其中Z軸從屏幕內指向屏幕外。 - 編號為①②③的矩形塊叫顯示層(Layer)。每一層有自己的屬性,例如顏色、透明度、所處屏幕的位置、寬、高等。除了屬性之外,每一層還有自己對應的顯示內容,也就是需要顯示的圖像。 在Android中,Surface系統工作時,會由SurfaceFlinger對這些按照Z軸排好序的顯示層進行圖像混合,混合后的圖像就是在屏幕上看到的美妙畫面了。這種按Z軸排序的方式符合我們在日常生活中的體驗,例如前面的物體會遮擋住后面的物體。 >[info] **注意**,Surface系統中定義了一個名為Layer類型的類,為了區分廣義概念上的Layer和代碼中的Layer,這里稱廣義層的Layer為顯示層,以免混淆。 Surface系統提供了三種屬性,一共四種不同的顯示層。簡單介紹一下: - 第一種屬性是eFXSurfaceNormal屬性,大多數的UI界面使用的就是這種屬性。它有兩種模式: 1)Normal模式,這種模式的數據,是通過前面的mView.draw(canvas)畫上去的。這也是絕大多數UI所采用的方式。 2)PushBuffer模式,這種模式對應于視頻播放、攝像機攝錄/預覽等應用場景。以攝像機為例,當攝像機運行時,來自Camera的預覽數據直接push到Buffer中,無須應用層自己再去draw了。 - 第二種屬性是eFXSurfaceBlur屬性,這種屬性的UI有點朦朧美,看起來很像隔著一層毛玻璃。 - 第三種屬性是eFXSurfaceDim屬性,這種屬性的UI看起來有點暗,好像隔了一層深色玻璃。從視覺上講,雖然它的UI看起來有點暗,但并不模糊。而eFXSurfaceBlur不僅暗,還有些模糊。 圖8-11展示了最后兩種類型的視覺效果圖,其中第一幅圖是Blur模式,第二幅圖是Dim模式。 :-: ![](http://img.blog.csdn.net/20150802162501322?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) :-: ![](http://img.blog.csdn.net/20150802162412912?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-11 Blur和Dim效果圖 注意,關于Surface系統的顯示層屬性定義,讀者可參考ISurfaceComposer.h。 本章將重點分析第一種屬性的兩類顯示層的工作原理。 2. FrameBuffer和PageFlipping 我們知道,在Audio系統中,音頻數據傳輸的過程是: - 由客戶端把數據寫到共享內存中。 - 然后由AudioFlinger從共享內存中取出數據再往Audio HAL中發送。 根據以上介紹可知,在音頻數據傳輸的過程中,共享內存起到了數據承載的重要作用。 無獨有偶,Surface系統中的數據傳輸也存在同樣的過程,但承載圖像數據的是鼎鼎大名的FrameBuffer(簡稱FB)。下面先來介紹FrameBuffer,然后再介紹Surface的數據傳輸過程。 (1)FrameBuffer的介紹 FrameBuffer的中文名叫幀緩沖,它實際上包括兩個不同的方面: - Frame:幀,就是指一幅圖像。在屏幕上看到的那幅圖像就是一幀。 - Buffer:緩沖,就是一段存儲區域,可這個區域存儲的是幀。 FrameBuffer的概念很清晰,它就是一個存儲圖形/圖像幀數據的緩沖。這個緩沖來自哪里?理解這個問題,需要簡單介紹一下Linux平臺的虛擬顯示設備FrameBuffer Device(簡稱FBD)。FBD是Linux系統中的一個虛擬設備,設備文件對應為/dev/fb%d(比如/dev/fb0)。這個虛擬設備將不同硬件廠商實現的真實設備統一在一個框架下,這樣應用層就可以通過標準的接口進行圖形/圖像的輸入和輸出了。圖8-12展示了FBD示意圖: :-: ![](http://img.blog.csdn.net/20150802162535966?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-12 Linux系統中的FBD示意圖 從上圖中可以看出,應用層通過標準的ioctl或mmap等系統調用,就可以操作顯示設備,用起來非常方便。這里,把mmap的調用列出來,相信大部分讀者都知道它的作用了。 FrameBuffer中的Buffer,就是通過mmap把設備中的顯存映射到用戶空間的,在這塊緩沖上寫數據,就相當于在屏幕上繪畫。 >[info] **注意**:上面所說的框架將引出另外一個概念Linux FrameBuffer(簡稱LFB)。LFB是Linux平臺提供的一種可直接操作FB的機制,依托這個機制,應用層通過標準的系統調用,就可以操作顯示設備了。從使用的角度來看,它和Linux Audio中的OSS有些類似。 為加深讀者對此節內容的理解,這里給出一個小例子,就是在DDMS工具中實現屏幕截圖功能,其代碼在framebuffer_service.c中,如下所示: **framebuffer_service.c** ~~~ struct fbinfo {//定義一個結構體 unsigned int version; unsigned int bpp; unsigned int size; unsigned int width; unsigned int height; unsigned int red_offset; unsigned int red_length; unsigned int blue_offset; unsigned int blue_length; unsigned int green_offset; unsigned int green_length; unsigned int alpha_offset; unsigned int alpha_length; } __attribute__((packed)); //fd是一個文件的描述符,這個函數的目的,是把當前屏幕的內容寫到一個文件中 void framebuffer_service(int fd, void *cookie) { structfb_var_screeninfo vinfo; intfb, offset; charx[256]; structfbinfo fbinfo; unsigned i, bytespp; //Android系統上的fb設備路徑在/dev/graphics目錄下 fb =open("/dev/graphics/fb0", O_RDONLY); if(fb< 0) goto done; //取出屏幕的屬性 if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) goto done; fcntl(fb, F_SETFD, FD_CLOEXEC); bytespp = vinfo.bits_per_pixel / 8; //根據屏幕的屬性填充fbinfo結構,這個結構要寫到輸出文件的頭部 fbinfo.version = DDMS_RAWIMAGE_VERSION; fbinfo.bpp = vinfo.bits_per_pixel; fbinfo.size = vinfo.xres * vinfo.yres * bytespp; fbinfo.width = vinfo.xres; fbinfo.height = vinfo.yres; /* 下面幾個變量和顏色格式有關,以RGB565為例,簡單介紹一下。 RGB565表示一個像素點中R分量為5位,G分量為6位,B分量為5位,并且沒有Alpha分量。 這樣一個像素點的大小為16位,占兩個字節,比RGB888格式的一個像素少一個字節(它一個像素是三個字節)。 x_length的值為x分量的位數,例如,RGB565中R分量就是5位。 x_offset的值代表x分量在內存中的位置。如RGB565一個像素占兩個字節,那么x_offeset 表示x分量在這兩個字節內存區域中的起始位置,但這個順序是反的,也就是B分量在前, R在最后。所以red_offset的值就是11,而blue_offset的值是0,green_offset的值是6。 這些信息在做格式轉換時(例如從RGB565轉到RGB888的時候)有用。 */ fbinfo.red_offset = vinfo.red.offset; fbinfo.red_length = vinfo.red.length; fbinfo.green_offset = vinfo.green.offset; fbinfo.green_length = vinfo.green.length; fbinfo.blue_offset = vinfo.blue.offset; fbinfo.blue_length = vinfo.blue.length; fbinfo.alpha_offset = vinfo.transp.offset; fbinfo.alpha_length = vinfo.transp.length; offset= vinfo.xoffset * bytespp; offset+= vinfo.xres * vinfo.yoffset * bytespp; //將fb信息寫到文件頭部 if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done; lseek(fb, offset, SEEK_SET); for(i= 0; i < fbinfo.size; i += 256) { if(readx(fb, &x, 256)) goto done;//讀取FBD中的數據 if(writex(fd, &x, 256)) goto done;//將數據寫到文件 } if(readx(fb, &x, fbinfo.size % 256)) goto done; if(writex(fd, &x, fbinfo.size % 256)) goto done; done: if(fb>= 0) close(fb); close(fd); } ~~~ 上面函數的目的就是截屏,這個例子可加深我們對FB的直觀感受,相信讀者下次再碰到FB時就不會犯怵了。 * * * * * **注意**:我們可根據這段代碼,寫一個簡單的Native可執行程序,然后adb push到設備上運行。注意上面寫到文件中的是RGB565格式的原始數據,如想在臺式機上看到這幅圖片,可將它轉換成BMP格式。我的個人博客上提供一個RGB565轉BMP的程序,讀者可以下載或自己另寫一個,這樣或許有助于更深入理解圖形/圖像方面的知識。 * * * * * 在繼續分析前,先來問一個問題: **前面在Audio系統中講過,CB對象通過讀寫指針來協調生產者/消費者的步調,那么Surface系統中的數據傳輸過程,是否也需通過讀寫指針來控制呢?** 答案是肯定的,但不像Audio中的CB那樣復雜。 (2)PageFlipping 圖形/圖像數據和音頻數據不太一樣,我們一般把音頻數據叫音頻流,它是沒有邊界的, 而圖形/圖像數據是一幀一幀的,是有邊界的。這一點非常類似UDP和TCP之間的區別。所以在圖形/圖像數據的生產/消費過程中,人們使用了一種叫PageFlipping的技術。 PageFlipping的中文名叫畫面交換,其操作過程如下所示: - 分配一個能容納兩幀數據的緩沖,前面一個緩沖叫FrontBuffer,后面一個緩沖叫BackBuffer。 - 消費者使用FrontBuffer中的舊數據,而生產者用新數據填充BackBuffer,二者互不干擾。 - 當需要更新顯示時,BackBuffer變成FrontBuffer,FrontBuffer變成BackBuffer。如此循環,這樣就總能顯示最新的內容了。這個過程很像我們平常的翻書動作,所以它被形象地稱為PageFlipping。 說白了,PageFlipping其實就是使用了一個只有兩個成員的幀緩沖隊列,以后在分析數據傳輸的時候還會見到諸如dequeue和queue的操作。 3. 圖像混合 我們知道,在AudioFlinger中有混音線程,它能將來自多個數據源的數據混合后輸出,那么,SurfaceFlinger是不是也具有同樣的功能呢? 答案是肯定的,否則它就不會叫Flinger了。Surface系統支持軟硬兩個層面的圖像混合: - 軟件層面的混合:例如使用copyBlt進行源數據和目標數據的混合。 - 硬件層面的混合:使用Overlay系統提供的接口。 無論是硬件還是軟件層面,都需將源數據和目標數據進行混合,混合需考慮很多內容,例如源的顏色和目標的顏色疊加后所產生的顏色。關于這方面的知識,讀者可以學習計算機圖形/圖像學。這里只簡單介紹一下copyBlt和Overlay。 - copyBlt,從名字上看,是數據拷貝,它也可以由硬件實現,例如現在很多的2D圖形加速就是將copyBlt改由硬件來實現,以提高速度的。但不必關心這些,我們只需關心如何調用copyBlt相關的函數進行數據混合即可。 - Overlay方法必須有硬件支持才可以,它主要用于視頻的輸出,例如視頻播放、攝像機攝像等,因為視頻的內容往往變化很快,所以如改用硬件進行混合效率會更高。 總體來說,Surface是一個比較龐大的系統,由于篇幅和精力所限,本章后面的內容將重點關注Surface系統的框架和工作流程。在掌握框架和流程后,讀者就可以在大的脈絡中迅速定位到自己感興趣的地方,然后展開更深入的研究了。 下面通過圖8-9所示的精簡流程,深入分析Android的Surface系統。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看