Android圖形顯示系統——下層顯示3:窗口系統

Android之窗口系統

要點

1.Android窗口系統通過C-S架構和一套Buffer循環機制實現,在保證安全穩定的前提下基本上做到了極致性能(無大塊內存拷貝,IPC通信內容最少)。
2.SurfaceFlinger創建Layer,將其中的BufferQueueProducer作爲IGraphicBufferProducer傳給應用側的Surface,因而構成窗口。
3.Surface是皮,BufferQueue是肉,通過這樣的皮肉關係構建了Buffer循環機制。Buffer循環機制不僅用於窗口系統,也用於視頻播放解碼流,相機拍照數據流等(Camera2.0架構)。

注:代碼基於Android 5.0

窗口系統接口

作爲一個應用,繪圖是自由的,基本上也是平臺無關的。但如果要把繪圖的結果顯示出來,就必須依賴平臺提供的窗口系統。好比我們寫篇文章出來容易,要投到雜誌上發表,就必須按雜誌社的格式,並通過審校等一堆流程,不然每個人都隨便發,肯定亂套了。

Android的窗口系統設計

窗口類型
Android爲應用層提供的窗口接口爲ANativeWindow。這個接口可用來調整配置參數,獲取圖形內存並送還觸發顯示。應用層是Buffer的生產者。
對於非GPU繪圖的應用,通過這個類去獲取圖形內存(dequeueBuffer),並在繪製完成之後送還(queueBuffer),讓顯示系統在合適的時機顯示。
對於GPU繪圖(嚴格來說,是使用EGL標準)的應用,在創建OpenGL上下文時將ANativeWindow的指針傳入,GPU的驅動會在合適的時候完成獲取內存和送還的操作。應用層只需要調用eglSwapBuffers換緩存即可。

Android的Windows接口

對應用層開放的windows接口定義在
system/core/include/system/windows.h
主要接口函數如下:

struct ANativeWindow
{
    /*......*/
    int     (*setSwapInterval)(struct ANativeWindow* window, int interval);//設置Buffer失效期限,當應用生產Buffer快於消費者(一般是顯示系統)的消費時,這個參數決定是否丟棄之前沒來得及消費的Buffer。
    int     (*query)(const struct ANativeWindow* window, int what, int* value);//查詢參數
    int     (*perform)(struct ANativeWindow* window,int operation, ... );//設置參數,其中也包括做連接
    int     (*dequeueBuffer)(struct ANativeWindow* window, struct ANativeWindowBuffer** buffer, int* fenceFd);//從隊列中取出一塊Buffer用於生產(一般是圖形渲染),若是第一次調用,會觸發Buffer的申請
    int     (*queueBuffer)(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer, int fenceFd);//將生產完成的Buffer送還
    int     (*cancelBuffer)(struct ANativeWindow* window,  struct ANativeWindowBuffer* buffer, int fenceFd);//釋放Buffer隊列中的Buffer,一般是disconnect時調用
};

用於perform和query接口的一些宏定義如下:

/*用於perform和query接口的宏*/
enum {
    NATIVE_WINDOW_SET_USAGE                 =  0,
    NATIVE_WINDOW_CONNECT                   =  1,   /* deprecated */
    NATIVE_WINDOW_DISCONNECT                =  2,   /* deprecated */
    NATIVE_WINDOW_SET_CROP                  =  3,   /* private */
    NATIVE_WINDOW_SET_BUFFER_COUNT          =  4,
    NATIVE_WINDOW_SET_BUFFERS_GEOMETRY      =  5,   /* deprecated */
    NATIVE_WINDOW_SET_BUFFERS_TRANSFORM     =  6,
    NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP     =  7,
    NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS    =  8,
    NATIVE_WINDOW_SET_BUFFERS_FORMAT        =  9,
    NATIVE_WINDOW_SET_SCALING_MODE          = 10,   /* private */
    NATIVE_WINDOW_LOCK                      = 11,   /* private */
    NATIVE_WINDOW_UNLOCK_AND_POST           = 12,   /* private */
    NATIVE_WINDOW_API_CONNECT               = 13,   /* private */
    NATIVE_WINDOW_API_DISCONNECT            = 14,   /* private */
    NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
    NATIVE_WINDOW_SET_POST_TRANSFORM_CROP   = 16,   /* private */
    NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */
    NATIVE_WINDOW_SET_SIDEBAND_STREAM       = 18,
    NATIVE_WINDOW_SET_BUFFERS_DATASPACE     = 19
};

窗口的創建與使用

Surface

自Android 4.2之後,FramebufferNativeWindow被廢棄,所有窗口均繼承Surface。Surface本身是一種ANativeWindow。

class Surface
    : public ANativeObjectBase<ANativeWindow, Surface, RefBase>/*Surface繼承於ANativeWindow*/
{
public:
    Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false);
    /*......*/
private:
    // ANativeWindow hooks
    /*這幾個hook函數對應於 window.h 中的接口函數*/
    static int hook_cancelBuffer(ANativeWindow* window,
            ANativeWindowBuffer* buffer, int fenceFd);
    static int hook_dequeueBuffer(ANativeWindow* window,
            ANativeWindowBuffer** buffer, int* fenceFd);
    static int hook_perform(ANativeWindow* window, int operation, ...);
    static int hook_query(const ANativeWindow* window, int what, int* value);
    static int hook_queueBuffer(ANativeWindow* window,
            ANativeWindowBuffer* buffer, int fenceFd);
    static int hook_setSwapInterval(ANativeWindow* window, int interval);

    static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
            ANativeWindowBuffer* buffer);
    static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
            ANativeWindowBuffer** buffer);
    static int hook_lockBuffer_DEPRECATED(ANativeWindow* window,
            ANativeWindowBuffer* buffer);
    static int hook_queueBuffer_DEPRECATED(ANativeWindow* window,
            ANativeWindowBuffer* buffer);
    /*.......*/
public:
    /*這兩個函數主要是CPU繪圖時調用,除了獲取,映射Buffer之外,額外將非髒區域從上一塊Buffer拷貝到本塊Buffer,以便渲染時只繪製髒區域*/
    virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
    virtual int unlockAndPost();
    /*.......*/
private:
    struct BufferSlot {
        sp<GraphicBuffer> buffer;
        Region dirtyRegion;
    };
    /*Buffer生產者,Surface*/
    sp<IGraphicBufferProducer> mGraphicBufferProducer;
    BufferSlot mSlots[NUM_BUFFER_SLOTS];
    /*通過native_window_set_buffers_dimensions改變,用於在合適的時機改變GraphicBuffer的長寬*/
    uint32_t mReqWidth;
    uint32_t mReqHeight;
    /*需求的GraphicBuffer格式,用於動態調整*/
    PixelFormat mReqFormat;
    /*需求Usage說明,影響GraphicBuffer的flags*/
    uint32_t mReqUsage;
    /*時間戳,用於判斷Buffer是否過期*/
    int64_t mTimestamp;
    /*Buffer的使用範圍*/
    Rect mCrop;
    /*Buffer後續變換需求,只包括水平、垂直翻轉,90度旋轉*/
    uint32_t mTransformHint;
    /*BufferProducer是否由使用Surface的App控制,這個主要是用來決定dequeueBuffer時是否堵塞*/
    bool mProducerControlledByApp;
    /*......*/
};

}; // namespace android

窗口的創建

用於圖形顯示的窗口,是由SurfaceFlinger進程負責創建的:
Surface創建
爲應用層創建Surface(窗口)時,SurfaceFlinger同步創建一個Layer,並將Layer的生產者關聯到Surface上。這樣,應用側便可以通過Surface申請Buffer,作爲生產者渲染圖像,送顯由Layer中的消費者負責。

Buffer循環機制

對於按一定幀率刷新的窗口系統,每一次渲染只有很有限的時間,頻繁地申請/釋放圖形內存是不可接受的。Android的做法是維護一個Buffer隊列,按生產者——消費者模式循環利用。這個Buffer就是上一章所述的GraphicBuffer。

Buffer的狀態

Buffer隊列池中持有固定數量的Buffer(由setBufferCount函數決定,一般是3塊),每個Buffer有四種狀態,決定其是否可以被生產者/消費者訪問。
Buffer狀態變化

Buffer的生產

序號化

由於Layer位於SurfaceFlinger進程中,GraphicBuffer是在SurfaceFlinger進程中創建的。應用層作爲生產者,使用時需要將其映射到自己的進程空間。在每次申請Buffer時都做一次映射很不明智。
很容易想到的一個方法是在應用層建一個GraphicBuffer隊列,和SurfaceFlinger中的Buffer隊列對應地映射起來,每次申請和返還時,以序號代替真實的GraphicBuffer傳替。Android也正是這麼做的。

dequeueBuffer

Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd)
這接口用於申請內存進行生產(渲染)。
於Surface側,它獲取Buffer的序列號,然後檢查是否已經同步過,若沒有同步過調用requestBuffer同步(映射共享內存)。
於BufferQueue側,它檢查是否有 FREE 標誌的Buffer,如果沒有,根據 mProducerControlledByApp 標誌決定返回錯誤碼或者等待。
fenceFd是BufferQueue返回給Surface的,生產者有義務去等fence。

queueBuffer

int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd)
於Surface側,它將Buffer送還給BufferQueue,但這不一定表示生產者用完了,消費者獲取到Buffer之後仍有義務等fence。
於BufferQueue側,接收到Buffer,將其放到一個可用隊列中,修改狀態,並且觸發監聽器的onFrameAvailable函數。

Buffer的消費

acquireBuffer

消費者獲取buffer,由於在queueBuffer時,會將Buffer放到一個隊列中,這時便從那個隊列去取。

releaseBuffer

消費者釋放buffer。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章