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

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                SF中的工作線程就是來做圖像混合的,比起AudioFlinger來,它相當簡單,下面是它的代碼: **SurfaceFlinger.cpp** ~~~ bool SurfaceFlinger::threadLoop() { waitForEvent();//① 等待什么事件呢? if (UNLIKELY(mConsoleSignals)) { handleConsoleEvents(); } if(LIKELY(mTransactionCount == 0)) { const uint32_t mask = eTransactionNeeded | eTraversalNeeded; uint32_t transactionFlags = getTransactionFlags(mask); if(LIKELY(transactionFlags)) { //Transaction(事務)處理,放到本節最后來討論 handleTransaction(transactionFlags); } } //②處理PageFlipping工作 handlePageFlip(); constDisplayHardware& hw(graphicPlane(0).displayHardware()); if (LIKELY(hw.canDraw() && !isFrozen())) { //③處理重繪 handleRepaint(); hw.compositionComplete(); //④投遞BackBuffer unlockClients(); postFramebuffer(); } else{ unlockClients(); usleep(16667); } returntrue; } ~~~ ThreadLoop一共有四個關鍵點,這里,分析除Transaction外的三個關鍵點。 1. waitForEvent SF工作線程一上來就等待事件,它會是什么事件呢?來看代碼: **SurfaceFlinger.cpp** ~~~ void SurfaceFlinger::waitForEvent() { while(true) { nsecs_t timeout = -1; const nsecs_t freezeDisplayTimeout = ms2ns(5000); ...... MessageList::value_type msg = mEventQueue.waitMessage(timeout); ......//還有一些和凍屏相關的內容 if(msg != 0) { switch (msg->what) { //千辛萬苦就等這一個重繪消息 case MessageQueue::INVALIDATE: return; } } } } ~~~ SF收到重繪消息后,將退出等待。那么,是誰發送的這個重繪消息呢?還記得在unlockCanvasAndPost函數中調用的signal嗎?它在SF端的實現代碼如下: **SurfaceFlinger** ~~~ void SurfaceFlinger::signal() const { const_cast<SurfaceFlinger*>(this)->signalEvent(); } void SurfaceFlinger::signalEvent() { mEventQueue.invalidate(); //往消息隊列中加入INVALIDATE消息 } ~~~ 2. 分析handlePageFlip SF工作線程從waitForEvent中返回后,下一步要做的就是處理事務和handlePageFlip了。先看handlePageFlip,從名字上可知,它和PageFlipping工作有關。 * * * * * **注意**:事務處理將在8.5.3節中介紹。 * * * * * 代碼如下所示: **SurfaceFlinger.cpp** ~~~ void SurfaceFlinger::handlePageFlip() { bool visibleRegions = mVisibleRegionsDirty; /* 還記得前面所說的mCurrentState嗎?它保存了所有顯示層的信息,而繪制的時候使用的 mDrawingState則保存了當前需要顯示的顯示層信息。 */ LayerVector& currentLayers = const_cast<LayerVector&>(mDrawingState.layersSortedByZ); //①調用lockPageFlip visibleRegions |= lockPageFlip(currentLayers); const DisplayHardware& hw =graphicPlane(0).displayHardware(); //取得屏幕的區域 const Region screenRegion(hw.bounds()); if (visibleRegions) { Region opaqueRegion; computeVisibleRegions(currentLayers, mDirtyRegion,opaqueRegion); mWormholeRegion = screenRegion.subtract(opaqueRegion); mVisibleRegionsDirty = false; } //② 調用unlockPageFlip unlockPageFlip(currentLayers); mDirtyRegion.andSelf(screenRegion); } ~~~ hanldePageFlip調用了兩個看起來是一對的函數:lockPageFlip和unlockPageFlip。這兩個函數會干些什么呢? (1)lockPageFlip的分析 先看lockPageFlip函數,代碼如下所示: **SurfaceFlinger.cpp** ~~~ bool SurfaceFlinger::lockPageFlip(constLayerVector& currentLayers) { boolrecomputeVisibleRegions = false; size_tcount = currentLayers.size(); sp<LayerBase> const* layers = currentLayers.array(); for(size_t i=0 ; i<count ; i++) { const sp<LayerBase>& layer = layers[i]; //調用每個顯示層的lockPageFlip layer->lockPageFlip(recomputeVisibleRegions); } returnrecomputeVisibleRegions; } ~~~ 假設當前的顯示層是Layer類型,那么得轉到Layer類去看它的lockPageFlip函數,代碼如下所示: **Layer.cpp** ~~~ void Layer::lockPageFlip(bool&recomputeVisibleRegions) { //lcblk是SharedBufferServer類型,調用retireAndLock函數將返回FrontBuffer的 //索引號 ssize_tbuf = lcblk->retireAndLock(); ...... mFrontBufferIndex = buf; //得到FrontBuffer對應的GraphicBuffer sp<GraphicBuffer> newFrontBuffer(getBuffer(buf)); if (newFrontBuffer != NULL) { //取出臟區域 const Region dirty(lcblk->getDirtyRegion(buf)); //和GraphicBuffer所表示的區域進行裁剪,得到一個臟區域 mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() ); const Layer::State& front(drawingState()); if(newFrontBuffer->getWidth() ==front.requested_w && newFrontBuffer->getHeight() ==front.requested_h) { if ((front.w != front.requested_w) || (front.h != front.requested_h)) { ...... //需要重新計算可見區域 recomputeVisibleRegions = true; } mFreezeLock.clear(); } } else{ mPostedDirtyRegion.clear(); } if(lcblk->getQueuedCount()) { mFlinger->signalEvent(); } /* 如果臟區域不為空,則需要繪制成紋理,reloadTexture將繪制一張紋理保存在 mTextures數組中,里邊涉及很多OpenGL的操作,讀者有興趣可以自己研究。 */ if(!mPostedDirtyRegion.isEmpty()) { reloadTexture( mPostedDirtyRegion ); } } ~~~ 我們知道,Layer的lockPageFlip將根據FrontBuffer的內容生成一張紋理。那么,unlockPageFlip會做些什么呢? (2)unlockPageFlip的分析 unlockPageFlip的代碼如下所示: **SurfaceFlinger.cpp** ~~~ void SurfaceFlinger::unlockPageFlip(constLayerVector& currentLayers) { constGraphicPlane& plane(graphicPlane(0)); constTransform& planeTransform(plane.transform()); size_tcount = currentLayers.size(); sp<LayerBase> const* layers = currentLayers.array(); for(size_t i=0 ; i<count ; i++) { const sp<LayerBase>& layer = layers[i]; //調用每個顯示層的unlockPageFlip,Layer的unlockPageFlip主要做一些 //區域的清理工作,讀者可以自己看看。 layer->unlockPageFlip(planeTransform, mDirtyRegion); } } ~~~ (3)handlePageFlip的總結 handlePageFlip的工作其實很簡單,以Layer類型為例來總結一下: 各個Layer需要從FrontBuffer中取得新數據,并生成一張OpenGL中的紋理。紋理可以看做是一個圖片,這個圖片的內容就是FrontBuffer中的圖像。 現在每一個Layer都準備好了新數據,下一步的工作當然就是繪制了。來看handleRepaint函數。 3. 分析handleRepaint函數 handleRepaint函數的代碼如下所示: **SurfaceFlinger.cpp** ~~~ void SurfaceFlinger::handleRepaint() { mInvalidRegion.orSelf(mDirtyRegion); if(mInvalidRegion.isEmpty()) { return; } ...... constDisplayHardware& hw(graphicPlane(0).displayHardware()); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); uint32_t flags = hw.getFlags(); if((flags & DisplayHardware::SWAP_RECTANGLE) || (flags & DisplayHardware::BUFFER_PRESERVED)) { ......//計算mDirtyRegion } // 在臟區域上進行繪制 composeSurfaces(mDirtyRegion); mDirtyRegion.clear(); } ~~~ 其中,composeSurfaces將不同的顯示層內容進行混合,其實就是按Z軸的順序由里到外依次繪制。當然,最后繪制的數據有可能遮蓋前面繪制的數據,代碼如下所示: **SurfaceFlinger.cpp** ~~~ void SurfaceFlinger::composeSurfaces(constRegion& dirty) { constSurfaceFlinger& flinger(*this); constLayerVector& drawingLayers(mDrawingState.layersSortedByZ); constsize_t count = drawingLayers.size(); sp<LayerBase> const* const layers = drawingLayers.array(); for(size_t i=0 ; i<count ; ++i) { const sp<LayerBase>& layer = layers[i]; const Region&visibleRegion(layer->visibleRegionScreen); if(!visibleRegion.isEmpty()) { const Region clip(dirty.intersect(visibleRegion)); if (!clip.isEmpty()) { layer->draw(clip); //調用各個顯示層的layer函數 } } } } ~~~ draw函數在LayerBase類中實現,代碼如下所示: **LayerBase.cpp** ~~~ void LayerBase::draw(const Region& inClip)const { ...... glEnable(GL_SCISSOR_TEST); onDraw(clip);//調用子類的onDraw函數 } ~~~ 至于Layer是怎么實現這個onDraw函數的,代碼如下所示: **Layer.cpp** ~~~ void Layer::onDraw(const Region& clip) const { intindex = mFrontBufferIndex; if(mTextures[index].image == EGL_NO_IMAGE_KHR) index = 0; GLuint textureName = mTextures[index].name; .... Region holes(clip.subtract(under)); if(!holes.isEmpty()) { clearWithOpenGL(holes); } return; } //index是FrontBuffer對應生成的紋理,在lockPageFlip函數中就已經生成了。 drawWithOpenGL(clip,mTextures[index]);//將紋理畫上去,里面有很多和OpenGL相關內容 } ~~~ drawWithOpenGL函數由LayerBase實現,看它是不是使用了這張紋理,代碼如下所示: **LayerBase.cpp** ~~~ void LayerBase::drawWithOpenGL(const Region&clip, const Texture& texture) const { constDisplayHardware& hw(graphicPlane(0).displayHardware()); constuint32_t fbHeight = hw.getHeight(); constState& s(drawingState()); //validateTexture函數內部將綁定指定的紋理 validateTexture(texture.name); //下面就是OpenGL操作函數了 glEnable(GL_TEXTURE_2D); ...... glMatrixMode(GL_TEXTURE); glLoadIdentity(); //坐標旋轉 switch(texture.transform) { case HAL_TRANSFORM_ROT_90: glTranslatef(0, 1, 0); glRotatef(-90, 0, 0, 1); break; case HAL_TRANSFORM_ROT_180: glTranslatef(1, 1, 0); glRotatef(-180, 0, 0, 1); break; case HAL_TRANSFORM_ROT_270: glTranslatef(1, 0, 0); glRotatef(-270, 0, 0, 1); break; } if (texture.NPOTAdjust) { //縮放處理 glScalef(texture.wScale, texture.hScale, 1.0f); } //使能紋理坐標 glEnableClientState(GL_TEXTURE_COORD_ARRAY); //設置頂點坐標 glVertexPointer(2, GL_FIXED, 0, mVertices); //設置紋理坐標 glTexCoordPointer(2, GL_FIXED, 0, texCoords); while(it != end) { const Rect& r = *it++; const GLint sy = fbHeight - (r.top + r.height()); //裁剪 glScissor(r.left, sy, r.width(), r.height()); //畫矩形 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } //禁止紋理坐標 glDisableClientState(GL_TEXTURE_COORD_ARRAY); } ~~~ 紋理綁定是OpenGL的常用函數,其代碼如下所示。 **LayerBase.cpp** ~~~ void LayerBase::validateTexture(GLinttextureName) const { //下面這個函數將綁定紋理 glBindTexture(GL_TEXTURE_2D, textureName); ......//其他一些設置 } ~~~ handleRepaint這個函數基本上就是按Z軸的順序對每一層進行重繪,重繪的方法就是使用OpenGL。 我在Android平臺上有幾個月的OpenGL開發經歷,還談不上很深刻,其中的一些資料,希望能夠給感興趣的讀者提供參考。 1)OpenGL的入門教材當選NeHe的資料,大略看前幾章即可。 2) Android平臺上關于OpenGL ES的開發,有一篇很詳細的Word文檔叫《OpenGL ESTutorial for Android》。該文詳細描述了在Android平臺上進行OpenGL開發的流程。大家可跟著這篇教材,在模擬器上做一些練習。那里面涉及到的一些基礎知識,從前面介紹的入門教材中可以學到。 3)有了前面兩點的基礎后,就需要對整個OpenGL有比較完整深入的了解了。我在那時所看的書是《OpenGL Programming Guide (7th Edition)》。該書很厚,有1000多頁。里面有一些內容可能與工作無涉,只要大概知道有那回事就行了,暫時不必深入學習,等需要時再進一步學習并運用。我在開發的項目中曾用到的光照、霧化等效果,都是之前先知道有這個東西,后來在項目中才逐漸學習運用的。 4)嵌入式平臺上用的其實是OpenGL ES。這里,還有一本書叫《OpenGL ES 2.0 Programming Guide》,它介紹了OpenGL ES的開發,讀者可認真修習。 5)在Android SDK文檔中,對OpenGL API的描述只寥寥數語。怎么辦?由于它使用了J2ME中的javax.microedition.khronos.opengles包,所以J2ME的SDK文檔中對OpenGL的API有著非常詳細的描述,讀者手頭應該要有一個J2ME的文檔。 6)如果想做深入開發,就不得不學習計算機圖形學了。我后來買了書,可惜沒時間學了。 4. unlockClients和postFrameBuffer的分析 在繪制完圖后,還有兩項工作需要做,一個涉及unlockClients函數,另外一個涉及postFrameBuffer函數,這兩個函數分別干了什么呢?unlockClients的代碼如下所示: **SurfaceFlinger.cpp** ~~~ void SurfaceFlinger::unlockClients() { constLayerVector& drawingLayers(mDrawingState.layersSortedByZ); constsize_t count = drawingLayers.size(); sp<LayerBase> const* const layers = drawingLayers.array(); for (size_t i=0 ; i<count ; ++i) { const sp<LayerBase>& layer = layers[i]; layer->finishPageFlip(); } } ~~~ 再看Layer的finishPageFlip函數,代碼如下所示: **Layer.cpp** ~~~ void Layer::finishPageFlip() { //釋放FrontBufferIndex status_t err = lcblk->unlock( mFrontBufferIndex ); } ~~~ 原來,unlockClients會釋放之前占著的FrontBuffer的索引號。下面看最后一個函數postFrameBuffer,代碼如下所示: **SurfaceFlinger.cpp** ~~~ void SurfaceFlinger::postFramebuffer() { if(!mInvalidRegion.isEmpty()) { const DisplayHardware& hw(graphicPlane(0).displayHardware()); const nsecs_t now = systemTime(); mDebugInSwapBuffers = now; //調用這個函數后,混合后的圖像就會傳遞到屏幕中顯示了 hw.flip(mInvalidRegion); mLastSwapBufferTime = systemTime() - now; mDebugInSwapBuffers = 0; mInvalidRegion.clear(); } } ~~~ flip將調用在DisplayHardware一節中提到的eglSwapBuffer函數,來完成FrameBuffer的PageFlip操作,代碼如下所示: **DisplayHardware.cpp** ~~~ void DisplayHardware::flip(const Region&dirty) const { checkGLErrors(); EGLDisplay dpy = mDisplay; EGLSurface surface = mSurface; ...... if(mFlags & PARTIAL_UPDATES) { mNativeWindow->setUpdateRectangle(dirty.getBounds()); } mPageFlipCount++; eglSwapBuffers(dpy, surface);//PageFlipping,此后圖像終于顯示在屏幕上了! } ~~~
                  <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>

                              哎呀哎呀视频在线观看