<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國際加速解決方案。 廣告
                這一節,分析精簡流程中的最后兩個函數lockCanvas和unlockCanvasAndPost。 1. lockCanvas分析 據前文分析可知,UI在繪制前都需要通過lockCanvas得到一塊存儲空間,也就是所說的BackBuffer。這個過程中最終會調用Surface的lock函數。其代碼如下所示: **Surface.cpp** ~~~ status_t Surface::lock(SurfaceInfo* other,Region* dirtyIn, bool blocking) { //傳入的參數中,other用來接收一些返回信息,dirtyIn表示需要重繪的區域 ...... if (mApiLock.tryLock() != NO_ERROR) {//多線程的情況下要鎖住 ...... returnWOULD_BLOCK; } //設置usage標志,這個標志在GraphicBuffer分配緩沖時有指導作用 setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); //定義一個GraphicBuffer,名字就叫backBuffer。 sp<GraphicBuffer>backBuffer; //①還記得我們說的2個元素的緩沖隊列嗎?下面的dequeueBuffer將取出一個空閑緩沖 status_terr = dequeueBuffer(&backBuffer); if (err== NO_ERROR) { //② 鎖住這塊buffer err = lockBuffer(backBuffer.get()); if(err == NO_ERROR) { const Rect bounds(backBuffer->width, backBuffer->height); Region scratch(bounds); Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch); ...... //mPostedBuffer是上一次繪畫時使用的Buffer,也就是現在的frontBuffer const sp<GraphicBuffer>& frontBuffer(mPostedBuffer); if (frontBuffer !=0 && backBuffer->width ==frontBuffer->width && backBuffer->height == frontBuffer->height && !(mFlags & ISurfaceComposer::eDestroyBackbuffer)) { const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion)); if (!copyback.isEmpty() && frontBuffer!=0) { /③把frontBuffer中的數據拷貝到BackBuffer中,這是為什么? copyBlt(backBuffer,frontBuffer, copyback); } } mDirtyRegion = newDirtyRegion; mOldDirtyRegion = newDirtyRegion; void* vaddr; //調用GraphicBuffer的lock得到一塊內存,內存地址被賦值給了vaddr, //后續的作畫將在這塊內存上展開 status_t res = backBuffer->lock( GRALLOC_USAGE_SW_READ_OFTEN |GRALLOC_USAGE_SW_WRITE_OFTEN, newDirtyRegion.bounds(),&vaddr); mLockedBuffer = backBuffer; //other用來接收一些信息。 other->w =backBuffer->width; //寬度信息 other->h =backBuffer->height; other->s =backBuffer->stride; other->usage =backBuffer->usage; other->format = backBuffer->format; other->bits = vaddr; //最重要的是這個內存地址 } } mApiLock.unlock(); returnerr; } ~~~ 在上面的代碼中,列出了三個關鍵點: - 調用dequeueBuffer得到一個空閑緩沖,也可以叫空閑緩沖出隊。 - 調用lockBuffer。 - 調用copyBlt函數,把frontBuffer數據拷貝到backBuffer中,這是為什么? 來分析這三個關鍵點。 (1)dequeueBuffer的分析 dequeueBuffer的目的很簡單,就是選取一個空閑的GraphicBuffer,其代碼如下所示: **Surface.cpp** ~~~ status_tSurface::dequeueBuffer(sp<GraphicBuffer>* buffer) { android_native_buffer_t* out; status_t err = dequeueBuffer(&out);//調用另外一個dequeueBuffer if(err == NO_ERROR) { *buffer = GraphicBuffer::getSelf(out); } returnerr; } ~~~ 這其中又調用了另外一個dequeueBuffer函數。它的代碼如下所示: **Surface.cpp** ~~~ intSurface::dequeueBuffer(android_native_buffer_t** buffer) { sp<SurfaceComposerClient> client(getClient()); //①調用SharedBufferClient的dequeue函數,它返回當前空閑的緩沖號 ssize_tbufIdx = mSharedBufferClient->dequeue(); const uint32_t usage(getUsage()); /* mBuffers就是我們前面在Surface創建中介紹的那個二元sp<GraphicBuffer>數組。 這里定義的backBuffer是一個引用類型,也就是說如果修改backBuffer的信息, 就相當于修改了mBuffers[bufIdx] */ const sp<GraphicBuffer>&backBuffer(mBuffers[bufIdx]); //mBuffers定義的GraphicBuffer使用的也是無參構造函數,所以此時還沒有真實的存儲被創建 if(backBuffer == 0 || //第一次進來滿足backBuffer為空這個條件 ((uint32_t(backBuffer->usage) & usage) != usage) || mSharedBufferClient->needNewBuffer(bufIdx)) { //調用getBufferLocked,需要進去看看。 err = getBufferLocked(bufIdx, usage); if(err == NO_ERROR) { mWidth =uint32_t(backBuffer->width); mHeight = uint32_t(backBuffer->height); } } ...... } ~~~ 上面列出了一個關鍵點,就是SharedBufferClient的dequeue函數,暫且記住這個調用,后面會有單獨章節分析生產/消費步調控制。先看getBufferLocked函數,其代碼如下所示: **Surface.cpp** ~~~ tatus_t Surface::getBufferLocked(int index, intusage) { sp<ISurface> s(mSurface); status_t err = NO_MEMORY; //注意這個currentBuffer也被定義為引用類型 sp<GraphicBuffer>&currentBuffer(mBuffers[index]); //終于用上了ISurface對象,調用它的requestBuffer得到指定索引index的Buffer sp<GraphicBuffer> buffer =s->requestBuffer(index, usage); if (buffer != 0) { err = mSharedBufferClient->getStatus(); if(!err && buffer->handle != NULL) { //getBufferMapper返回GraphicBufferMapper對象 //調用它的registerBuffer干什么?這個問題我們在8.4.7節回答 err = getBufferMapper().registerBuffer(buffer->handle); if (err == NO_ERROR) { //把requestBuffer得到的值賦給currentBuffer,由于currentBuffer是引用類型, //實際上相當于mBuffers[index]=buffer currentBuffer = buffer; //設置currentBuffer的編號 currentBuffer->setIndex(index); mNeedFullUpdate = true; } }else { err = err<0 ? err : NO_MEMORY; } return err; } ~~~ 至此,getBufferLocked的目的,已比較清晰了: - 調用ISurface的requestBuffer得到一個GraphicBuffer對象,這個GraphicBuffer對象被設置到本地的mBuffers數組中。看來Surface定義的這兩個GraphicBuffer和Layer定義的兩個GraphicBuffer是有聯系的,所以圖8-18中只畫了兩個GraphicBuffer。 我們已經知道,ISurface的Bn端實際上是定義在Layer.類中的SurfaceLayer,下面來看它實現的requestBuffer。由于SurfaceLayer是Layer的內部類,它的工作最終都會交給Layer來處理,所以這里可直接看Layer的requestBuffer函數: **Layer.cpp** ~~~ sp<GraphicBuffer> Layer::requestBuffer(intindex, int usage) { sp<GraphicBuffer> buffer; sp<Client> ourClient(client.promote()); //lcblk就是那個SharedBufferServer對象,下面這個調用確保index號GraphicBuffer //沒有被SF當做FrontBuffer使用。 status_t err = lcblk->assertReallocate(index); ...... if(err != NO_ERROR) { return buffer; } uint32_t w, h; { Mutex::Autolock _l(mLock); w= mWidth; h= mHeight; /* mBuffers是SF端創建的一個二元數組,這里取出第index個元素,之前說過, mBuffers使用的也是GraphicBuffer的無參構造函數,所以此時也沒有真實存儲被創建。 */ buffer = mBuffers[index]; mBuffers[index].clear(); } constuint32_t effectiveUsage = getEffectiveUsage(usage); if(buffer!=0 && buffer->getStrongCount() == 1) { //①分配物理存儲,后面會分析這個。 err = buffer->reallocate(w, h, mFormat, effectiveUsage); } else{ buffer.clear(); //使用GraphicBuffer的有參構造,這也使得物理存儲被分配 buffer = new GraphicBuffer(w, h, mFormat, effectiveUsage); err = buffer->initCheck(); } ...... if(err == NO_ERROR && buffer->handle != 0) { Mutex::Autolock _l(mLock); if(mWidth && mHeight) { mBuffers[index] = buffer; mTextures[index].dirty = true; }else { buffer.clear(); } } returnbuffer;//返回 } ~~~ 不管怎樣,此時跨進程的這個requestBuffer返回的GraphicBuffer,已經和一塊物理存儲綁定到一起了。所以dequeueBuffer順利返回了它所需的東西。接下來則需調用lockBuffer。 (2)lockBuffer的分析 lockBuffer的代碼如下所示: **Surface.cpp** ~~~ int Surface::lockBuffer(android_native_buffer_t*buffer) { sp<SurfaceComposerClient> client(getClient()); status_t err = validate(); int32_t bufIdx = GraphicBuffer::getSelf(buffer)->getIndex(); err =mSharedBufferClient->lock(bufIdx); //調用SharedBufferClient的lock return err; } ~~~ 來看這個lock函數: **SharedBufferStack.cpp** ~~~ status_t SharedBufferClient::lock(int buf) { LockCondition condition(this, buf);//這個buf是BackBuffer的索引號 status_t err = waitForCondition(condition); returnerr; } ~~~ * * * * * **注意**,給waitForCondition函數傳遞的是一個LockCondition類型的對象,前面所說的函數對象的作用將在這里見識到,先看waitForCondition函數: * * * * * **SharedBufferStack.h** ~~~ template <typename T> //這是一個模板函數 status_t SharedBufferBase::waitForCondition(Tcondition) { constSharedBufferStack& stack( *mSharedStack ); SharedClient& client( *mSharedClient ); constnsecs_t TIMEOUT = s2ns(1); Mutex::Autolock _l(client.lock); while((condition()==false) && //注意這個condition()的用法 (stack.identity == mIdentity) && (stack.status == NO_ERROR)) { status_t err = client.cv.waitRelative(client.lock, TIMEOUT); if(CC_UNLIKELY(err != NO_ERROR)) { if (err == TIMED_OUT) { if (condition()) {//注意這個:condition(),condition是一個對象 break; } else { } } else { return err; } } } return(stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status; } ~~~ waitForCondition函數比較簡單,就是等待一個條件為真,這個條件是否滿足由condition()這條語句來判斷。但這個condition不是一個函數,而是一個對象,這又是怎么回事? 這就是Funcition Object(函數對象)的概念。函數對象的本質是一個對象,不過是重載了操作符(),這和重載操作符+、-等沒什么區別。可以把它當作是一個函數來看待。 為什么需要函數對象呢?因為對象可以保存信息,所以調用這個對象的()函數就可以利用這個對象的信息了。 來看condition對象的()函數。剛才傳進來的是LockCondition,它的()定義如下: **SharedBufferStack.cpp** ~~~ boolSharedBufferClient::LockCondition::operator()() { //stack、buf等都是這個對象的內部成員,這個對象的目的就是根據讀寫位置判斷這個buffer是 //否空閑。 return(buf != stack.head || (stack.queued > 0 && stack.inUse != buf)); } ~~~ SharedBufferStack的讀寫控制,比Audio中的環形緩沖看起來要簡單,實際上它卻比較復雜。本章會在擴展部分進行分析。這里給讀者準備一個問題,也是我之前百思不得其解的問題: 既然已經調用dequeue得到了一個空閑緩沖,為什么這里還要lock呢? (3)拷貝舊數據 在第三個關鍵點中,可看到這樣的代碼: **Surface.cpp** ~~~ status_t Surface::lock(SurfaceInfo* other,Region* dirtyIn, bool blocking) { ...... const sp<GraphicBuffer>& frontBuffer(mPostedBuffer); if (frontBuffer !=0 && backBuffer->width ==frontBuffer->width && backBuffer->height == frontBuffer->height && !(mFlags & ISurfaceComposer::eDestroyBackbuffer)) { const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion)); if (!copyback.isEmpty() && frontBuffer!=0) { //③把frontBuffer中的數據拷貝到BackBuffer中,這是為什么? copyBlt(backBuffer,frontBuffer, copyback); } } ...... } ~~~ 上面這段代碼所解決的,其實是下面這個問題: 在大部分情況下,UI只有一小部分會發生變化(例如一個按鈕被按下去,導致顏色發生變化),這一小部分UI只對應整個GraphicBuffer中的一小塊存儲(就是在前面代碼中見到的dirtyRegion),如果整塊存儲都更新,則會極大地浪費資源。怎么辦? 這就需要將變化的圖像和沒有發生變化的圖像進行疊加。上一次繪制的信息保存在mPostedBuffer中,而這個mPostedBuffer則要在unLockAndPost函數中設置。這里將根據需要,把mPostedBuffer中的舊數據拷貝到BackBuffer中。后續的繪畫只要更新臟區域就可以了,這會節約不少資源。 OK,lockCanvas返回后,應用層將在這塊畫布上盡情作畫。假設現在已經在BackBuffer上繪制好了圖像,下面就要通過unlockCanvasAndPost進行后續工作了。一起來看。 2. unlockCanvasAndPost的分析 進入精簡流程的最后一步,就是unlockCanvasAndPost函數,它的代碼如下所示: **Surface.cpp** ~~~ status_t Surface::unlockAndPost() { //調用GraphicBuffer的unlock函數 status_t err = mLockedBuffer->unlock(); //get返回這個GraphicBuffer的編號,queueBuffer將含有新數據的緩沖加入隊中。 err =queueBuffer(mLockedBuffer.get()); mPostedBuffer = mLockedBuffer; //保存這個BackBuffer為mPostedBuffer mLockedBuffer = 0; returnerr; } ~~~ 來看queueBuffer調用,代碼如下所示: **Surface.cpp** ~~~ intSurface::queueBuffer(android_native_buffer_t* buffer) { sp<SurfaceComposerClient> client(getClient()); int32_t bufIdx =GraphicBuffer::getSelf(buffer)->getIndex(); //設置臟Region mSharedBufferClient->setDirtyRegion(bufIdx,mDirtyRegion); //更新寫位置。 err =mSharedBufferClient->queue(bufIdx); if (err== NO_ERROR) { //client是BpSurfaceFlinger,調用它的signalServer,這樣SF就知道新數據準備好了 client->signalServer(); } returnerr; } ~~~ 這里,與讀寫控制有關的是queue函數,其代碼如下所示: **SharedBufferStack.cpp** ~~~ status_t SharedBufferClient::queue(int buf) { //QueueUpdate也是一個函數對象 QueueUpdate update(this); //調用updateCondition函數。 status_t err = updateCondition( update ); SharedBufferStack& stack( *mSharedStack ); constnsecs_t now = systemTime(SYSTEM_TIME_THREAD); stack.stats.totalTime = ns2us(now - mDequeueTime[buf]); returnerr; } ~~~ 這個updateCondition函數的代碼如下所示: **SharedBufferStack.h** ~~~ template <typename T> status_t SharedBufferBase::updateCondition(Tupdate) { SharedClient& client( *mSharedClient ); Mutex::Autolock _l(client.lock); ssize_t result = update();//調用update對象的()函數 client.cv.broadcast(); //觸發同步對象 returnresult; } ~~~ updateCondition函數和前面介紹的waitForCondition函數一樣,都是使用的函數對象。queue操作使用的是QueueUpdate類,關于它的故事,將在拓展部分討論。 3. lockCanvas和unlockCanvasAndPost的總結 總結一下lockCanvas和unlockCanvasAndPost這兩個函數的工作流程,用圖8-20表示: :-: ![](http://img.blog.csdn.net/20150802162842059?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-20 lockCanvas和unlockCanvasAndPost流程總結
                  <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>

                              哎呀哎呀视频在线观看