<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>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                GraphicBuffer是Surface系統中一個高層次的顯示內存管理類,它封裝了和硬件相關的一些細節,簡化了應用層的處理邏輯。先來認識一下它。 1. 初識GraphicBuffer GraphicBuffer的代碼如下所示: **GraphicBuffer.h** ~~~ class GraphicBuffer :public EGLNativeBase<android_native_buffer_t, GraphicBuffer,LightRefBase<GraphicBuffer>>, public Flattenable ~~~ 其中,EGLNativeBase是一個模板類。它的定義,代碼如下所示: **Android_natives.h** ~~~ template <typename NATIVE_TYPE, typenameTYPE, typename REF> class EGLNativeBase : public NATIVE_TYPE, publicREF ~~~ 通過替換,可得到GraphicBuffer的派生關系,如圖8-21所示: :-: ![](http://img.blog.csdn.net/20150802162900888?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-21 GraphicBuffer派生關系的示意圖 從圖中可以看出: - 從LightRefBase派生使GraphicBuffer支持輕量級的引用計數控制。 - 從Flattenable派生使GraphicBuffer支持序列化,它的flatten和unflatten函數用于序列化和反序列化,這樣,GraphicBuffer的信息就可以存儲到Parcel包中并被Binder傳輸了。 另外,圖中的android_native_buffer_t是GraphicBuffer的父類,它是一個struct結構體。可以將C++語言中的struct和class當作同一個東西,所以GraphicBuffer能從它派生。其代碼如下所示: **android_native_buffer.h** ~~~ typedef struct android_native_buffer_t { #ifdef __cplusplus android_native_buffer_t() { common.magic = ANDROID_NATIVE_BUFFER_MAGIC; common.version = sizeof(android_native_buffer_t); memset(common.reserved, 0, sizeof(common.reserved)); } #endif //這個android_native_base_t是struct的第一個成員,根據C/C++編譯的特性,這個成員 //在它的派生類對象所占有的內存中也是排第一個。 structandroid_native_base_t common; intwidth; intheight; intstride; intformat; intusage; void* reserved[2]; //這是一個關鍵成員,保存一些和顯示內存分配/管理相關的內容 buffer_handle_t handle; void*reserved_proc[8]; } android_native_buffer_t; ~~~ GraphicBuffer和顯示內存分配相關的部分主要集中在buffer_handle_t這個變量上,它實際上是一個指針,定義如下: **gralloc.h** ~~~ typedef const native_handle* buffer_handle_t; ~~~ native_handle的定義如下: **native_handle.h** ~~~ typedef struct { intversion; /* version值為sizeof(native_handle_t) */ intnumFds; intnumInts; intdata[0]; /* data是數據存儲空間的首地址 */ } native_handle_t; typedef native_handle_t native_handle; ~~~ 讀者可能要問,一個小小的GraphicBuffer為什么這么復雜?要回答這個問題,應先對GraphicBuffer有比較全面的了解。按照圖8-20中的流程來看GraphicBuffer。 2. GraphicBuffer和存儲的分配 GraphicBuffer的構造函數最有可能分配存儲了。注意,流程中使用的是無參構造函數,所以應先看無參構造函數。 (1)無參構造函數的分析 代碼如下所示: **GraphicBuffer.cpp** ~~~ GraphicBuffer::GraphicBuffer() :BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mVStride(0), mIndex(-1) { /* 其中mBufferMapper為GraphicBufferMapper類型,它的創建采用的是單例模式,也就是每個 進程只有一個GraphicBufferMapper對象,讀者可以去看看get的實現。 */ width = height= stride= format= usage = 0; handle= NULL; //handle為空 } ~~~ 在無參構造函數中沒有發現和存儲分配有關的操作。那么,根據流程,下一個有可能的地方就是reallocate函數了。 (2)reallocate的分析 Reallocate的代碼如下所示: **GraphicBuffer.cpp** ~~~ status_t GraphicBuffer::reallocate(uint32_t w,uint32_t h, PixelFormat f, uint32_t reqUsage) { if(mOwner != ownData) return INVALID_OPERATION; if(handle) {//handle值在無參構造函數中初始化為空,所以不滿足if的條件 GraphicBufferAllocator& allocator(GraphicBufferAllocator::get()); allocator.free(handle); handle = 0; } returninitSize(w, h, f, reqUsage);//調用initSize函數 } ~~~ InitSize函數的代碼如下所示: **GraphicBuffer.cpp** ~~~ status_t GraphicBuffer::initSize(uint32_t w,uint32_t h, PixelFormat format, uint32_t reqUsage) { if(format == PIXEL_FORMAT_RGBX_8888) format = PIXEL_FORMAT_RGBA_8888; /* GraphicBufferAllocator才是真正的存儲分配的管理類,它的創建也是采用的單例模式, 也就是每個進程只有一個GraphicBufferAllocator對象 */ GraphicBufferAllocator& allocator =GraphicBufferAllocator::get(); //調用GraphicBufferAllocator的alloc來分配存儲,注意handle作為指針 //被傳了進去,看來handle的值會被修改 status_t err = allocator.alloc(w, h, format, reqUsage, &handle,&stride); if(err == NO_ERROR) { this->width = w; this->height = h; this->format = format; this->usage = reqUsage; mVStride = 0; } returnerr; } ~~~ (3)GraphicBufferAllocator的介紹 從上面的代碼中可以發現,GraphicBuffer的存儲分配和GraphicBufferAllocator有關。一個小小的存儲分配為什么需要經過這么多道工序呢?還是先來看GraphicBufferAllocator,代碼如下所示: **GraphicBufferAllocator.cpp** ~~~ GraphicBufferAllocator::GraphicBufferAllocator() :mAllocDev(0) { hw_module_t const* module; //調用hw_get_module,得到hw_module_t interr = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); if (err == 0) { //調用gralloc_open函數,注意我們把module參數傳了進去。 gralloc_open(module, &mAllocDev); } } ~~~ GraphicBufferAllocator在創建時,會首先調用hw_get_module取出一個hw_module_t類型的對象。從名字上看,它和硬件平臺有關系。它會加載一個叫libgralloc.硬件平臺名.so的動態庫。比如,我的HTC G7手機上加載的庫是/system/lib/hw/libgraolloc.qsd-8k.so。這個庫的源代碼在hardware/msm7k/libgralloc-qsd8k目錄下。 這個庫有什么用呢?簡言之,就是為了分配一塊用于顯示的內存,但為什么需要這種層層封裝呢?答案很簡單: 封裝的目的就是為了屏蔽不同硬件平臺的差別。 讀者可通過執行adb getprop ro.board.platform命令,得到具體手機上硬件平臺的名字。圖8-22總結了GraphicBufferAllocator分配內存的途徑。這部分代碼,讀者可參考hardware/libhardware/hardware.c和hardware/msm7k/libgralloc-qsd8k/gralloc.cpp,后文將不再深入探討和硬件平臺有關的知識。 :-: ![](http://img.blog.csdn.net/20150802163035193?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-22 GraphicBufferAllocator內存的分配途徑 >[warning] **注意**,這里是以G7的libgralloc.qsk-8k.so為示例的。其中pmem設備用來創建一塊連續的內存,因為有些硬件設備(例如Camera)工作時需要使用一塊連續的內存,對于這種情況,一般就會使用pmem設備來分配內存。 這里,僅討論圖8-22中與硬件無關的分配方式。在這種情況下,將使用ashmem分配共享內存。下面看GraphicBufferAllocator的alloc函數,其代碼如下所示: **GraphicBufferAllocator.cpp** ~~~ status_t GraphicBufferAllocator::alloc(uint32_tw, uint32_t h, PixelFormat format,int usage, buffer_handle_t* handle, int32_t*stride) { //根據前面的定義可知buffer_handle_t為native_handle_t*類型 status_t err; if (usage & GRALLOC_USAGE_HW_MASK) { err =mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride); } else { //SW分配,可以做到和HW無關了。 err = sw_gralloc_handle_t::alloc(w, h, format, usage, handle, stride); } ...... returnerr; } ~~~ 下面,來看軟件分配的方式: **GraphicBufferAllocator.cpp** ~~~ status_t sw_gralloc_handle_t::alloc(uint32_t w,uint32_t h, int format, int usage, buffer_handle_t* pHandle, int32_t*pStride) { intalign = 4; intbpp = 0; ......//格式轉換 size_tbpr = (w*bpp + (align-1)) & ~(align-1); size_tsize = bpr * h; size_tstride = bpr / bpp; size =(size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1); //直接使用了ashmem創建共享內存 int fd= ashmem_create_region("sw-gralloc-buffer", size); ...... //進行內存映射,得到共享內存起始地址 void*base = mmap(0, size, prot, MAP_SHARED, fd, 0); sw_gralloc_handle_t* hnd = new sw_gralloc_handle_t(); hnd->fd = fd;//保存文件描述符 hnd->size = size;//保存共享內存的大小 hnd->base = intptr_t(base);//intptr_t將void*類型轉換成int*類型 hnd->prot = prot;//保存屬性 *pStride = stride; *pHandle = hnd; //pHandle就是傳入的那個handle變量的指針,這里對它進行賦值 returnNO_ERROR; } ~~~ 我們知道,調用GraphicBuffer的reallocate函數后,會導致物理存儲被分配。前面曾說過,Layer會創建兩個GraphicBuffer,而Native Surface端也會創建兩個GraphicBuffer,那么這兩個GraphicBuffer是怎么建立聯系的呢?為什么說native_handle_t是GraphicBuffer的精髓呢? 3. flatten和unflatten的分析 試想,Native Surface的GraphicBuffer是怎么和Layer的GraphicBuffer建立聯系的: 先通過requestBuffer函數返回一個GraphicBuffer,然后這個GraphicBuffer被Native Surface保存。 這中間的過程其實是一個mini版的乾坤挪移,來看看,代碼如下所示: **ISurface.cpp** ~~~ //requestBuffer的響應端 status_t BnSurface::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case REQUEST_BUFFER: { CHECK_INTERFACE(ISurface, data, reply); int bufferIdx = data.readInt32(); int usage = data.readInt32(); sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage)); ...... /* requestBuffer的返回值被寫到Parcel包中,由于GraphicBuffer從 Flattenable類派生,這將導致它的flatten函數被調用 */ return reply->write(*buffer); } ....... } //再來看請求端的處理,在BpSurface中 virtual sp<GraphicBuffer> requestBuffer(intbufferIdx, int usage) { Parcel data, reply; data.writeInterfaceToken(ISurface::getInterfaceDescriptor()); data.writeInt32(bufferIdx); data.writeInt32(usage); remote()->transact(REQUEST_BUFFER, data, &reply); sp<GraphicBuffer> buffer = new GraphicBuffer(); reply.read(*buffer);//Parcel調用unflatten函數把信息反序列化到這個buffer中。 return buffer;//requestBuffer實際上返回的是本地new出來的這個GraphicBuffer } ~~~ 通過上面的代碼可以發現,挪移的關鍵體現在flatten和unflatten函數上。請看: (1)flatten的分析 flatten的代碼如下所示: **GraphicBuffer.cpp** ~~~ status_t GraphicBuffer::flatten(void* buffer,size_t size, int fds[], size_t count) const { //buffer是裝載數據的緩沖區,由Parcel提供 ...... if(handle) { buf[6] = handle->numFds; buf[7] = handle->numInts; native_handle_t const* const h = handle; //把handle的信息也寫到buffer中 memcpy(fds, h->data, h->numFds*sizeof(int)); memcpy(&buf[8], h->data + h->numFds,h->numInts*sizeof(int)); } returnNO_ERROR; } ~~~ flatten的工作就是把GraphicBuffer的handle變量信息寫到Parcel包中。那么接收端如何使用這個包呢?這就是unflatten的工作了。 (2)unflatten分析 unflatten的代碼如下所示: **GraphicBuffer.cpp** ~~~ status_t GraphicBuffer::unflatten(void const*buffer, size_t size, int fds[], size_t count) { ...... if(numFds || numInts) { width = buf[1]; height = buf[2]; stride = buf[3]; format = buf[4]; usage = buf[5]; native_handle* h =native_handle_create(numFds, numInts); memcpy(h->data, fds, numFds*sizeof(int)); memcpy(h->data + numFds, &buf[8],numInts*sizeof(int)); handle = h;//根據Parcel包中的數據還原一個handle } else{ width = height = stride = format = usage = 0; handle = NULL; } mOwner= ownHandle; returnNO_ERROR; } ~~~ unflatten最重要的工作是,根據Parcel包中native_handle的信息,在Native Surface端構造一個對等的GraphicBuffer。這樣,Native Surface端的GraphicBuffer實際上就和Layer端的GraphicBuffer管理著同一塊共享內存。 3. registerBuffer的分析 registerBuffer有什么用呢?上一步調用unflatten后得到了代表共享內存的文件句柄,regiserBuffer的目的就是對它進行內存映射,代碼如下所示: **GraphicBufferMapper.cpp** ~~~ status_tsw_gralloc_handle_t::registerBuffer(sw_gralloc_handle_t* hnd) { if (hnd->pid != getpid()) { //原來是做一次內存映射操作 void* base = mmap(0, hnd->size, hnd->prot, MAP_SHARED, hnd->fd,0); ...... //base保存著共享內存的起始地址 hnd->base = intptr_t(base); } returnNO_ERROR; } ~~~ 4. lock和unlock的分析 GraphicBuffer在使用前需要通過lock來得到內存地址,使用完后又會通過unlock釋放這塊地址。在SW分配方案中,這兩個函數實現卻非常簡單,如下所示: **GraphicBufferMapper.cpp** ~~~ //lock操作 int sw_gralloc_handle_t::lock(sw_gralloc_handle_t*hnd, int usage, int l, int t, int w, int h, void** vaddr) { *vaddr= (void*)hnd->base;//得到共享內存的起始地址,后續作畫就使用這塊內存了。 returnNO_ERROR; } //unlock操作 status_tsw_gralloc_handle_t::unlock(sw_gralloc_handle_t* hnd) { returnNO_ERROR;//沒有任何操作 } ~~~ 對GraphicBuffer的介紹就到這里。雖然采用的是SW方式,但是相信讀者也能通過樹木領略到森林的風采。從應用層角度看,可以把GraphicBuffer當做一個構架在共享內存之上的數據緩沖。對想深入研究的讀者,我建議可按圖8-20中的流程來分析。因為流程體現了調用順序,表達了調用者的意圖和目的,只有把握了流程,分析時才不會迷失在茫茫的源碼海洋中,才不會被不熟悉的知識阻攔前進的腳步。
                  <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>

                              哎呀哎呀视频在线观看