Android系統(tǒng)_Surface繪制流程分析

基于API 23

前篇:Android系統(tǒng)_Surface創(chuàng)建流程分析

申請(qǐng)Buffer

ViewRootImpl.draw

執(zhí)行遍歷 > 執(zhí)行Draw > draw方法 > 軟件繪制流程


private void performTraversals() {
    ...
    relayoutWindow(params, viewVisibility, insetsPending);
    ...
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    ...         
    performLayout(lp, mWidth, mHeight);
    ...
    performDraw();
    ...
}

private void performDraw() {
    draw(fullRedrawNeeded);
}

private void draw(boolean fullRedrawNeeded) {
    if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
        // 硬件加速 寥粹,繪制繪制流程
        if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
             ...
            mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
        } else {
          ...
           // 軟件繪制 流程
            if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
                return;
            }
    }
}

ViewRootImpl.drawSoftware

主要三個(gè)步驟 申請(qǐng)Buffer集峦、繪制衰伯、繪制完成

private boolean drawSoftware(Surface surface, AttachInfo attachInfo,...) {
    // Draw with software renderer.
    final Canvas canvas;
    ...
    canvas = mSurface.lockCanvas(dirty);  //申請(qǐng)Buffer
    ...
    mView.draw(canvas);  //繪制
    ...
    mSurface.unlockCanvasAndPost(canvas);  //繪制完成
}

Surface.lockCanvas

執(zhí)行JNI層的nativeLockCanvas平夜,mNativeObject就是native層Surface指針

public Canvas lockCanvas(Rect inOutDirty)
       throws Surface.OutOfResourcesException, IllegalArgumentException {
   synchronized (mLock) {
       checkNotReleasedLocked();
       
       mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
       return mCanvas;
   }
}

android_view_Surface.cpp

創(chuàng)建一個(gè)Rect對(duì)象塘秦,確定要重繪制的區(qū)域昌妹,執(zhí)行Surface的lock方法來(lái)申請(qǐng)bugger橘忱,然后新建了一個(gè)SKBitmap紫岩,設(shè)置了內(nèi)存地址,并把這個(gè)bitmap放入了Canvas中

static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
    sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject)); //轉(zhuǎn)換指針
    ...
    Rect dirtyRect;
    Rect* dirtyRectPtr = NULL;

    if (dirtyRectObj) {
        dirtyRect.left   = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
        dirtyRect.top    = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
        dirtyRect.right  = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
        dirtyRect.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
        dirtyRectPtr = &dirtyRect;
    }
    
    // 申請(qǐng)內(nèi)存Buffer
    ANativeWindow_Buffer outBuffer;
    status_t err = surface->lock(&outBuffer, dirtyRectPtr);
    
    ...
    SkImageInfo info = SkImageInfo::Make(outBuffer.width, outBuffer.height,
                                     convertPixelFormat(outBuffer.format),
                                     kPremul_SkAlphaType);               
    
    // 新建一個(gè)SkBitmap 并進(jìn)行一系列設(shè)置
    SkBitmap bitmap;
    ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
    bitmap.setInfo(info, bpr);
    if (outBuffer.width > 0 && outBuffer.height > 0) {
        bitmap.setPixels(outBuffer.bits);
    } else {
        // be safe with an empty bitmap.
        bitmap.setPixels(NULL);
    }
    // 把創(chuàng)建的bitmap 設(shè)置到Canvas中
    Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
    nativeCanvas->setBitmap(bitma
    if (dirtyRectPtr) {
        nativeCanvas->clipRect(dirtyRect.left, dirtyRect.top,
                dirtyRect.right, dirtyRect.bottom);
    
    if (dirtyRectObj) {
        env->SetIntField(dirtyRectObj, gRectClassInfo.left,   dirtyRect.left);
        env->SetIntField(dirtyRectObj, gRectClassInfo.top,    dirtyRect.top);
        env->SetIntField(dirtyRectObj, gRectClassInfo.right,  dirtyRect.right);
        env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, dirtyRect.bottom);
    
    // Create another reference to the surface and return it.  This reference
    // should be passed to nativeUnlockCanvasAndPost in place of mNativeObject,
    // because the latter could be replaced while the surface is locked.
    sp<Surface> lockedSurface(surface);
    lockedSurface->incStrong(&sRefBaseOwner);
    return (jlong) lockedSurface.get();    
}

Surface.cpp

通過(guò)dequeueBuffer獲取一個(gè)ANativeWindowBuffer吝镣,之后構(gòu)造一個(gè)GraphicBuffer堤器,這個(gè)bugger用來(lái)傳遞繪制的元數(shù)據(jù)
BufferQueueProducer中dequeueBuffer,將分配的內(nèi)存放到mSlots中末贾,outSlot就是給應(yīng)用進(jìn)程mSlots的序號(hào)
BufferQueueProducer中requestBuffer闸溃,根據(jù)序號(hào),從mSlots拿到buffer

status_t Surface::lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds){

    ANativeWindowBuffer* out; int fenceFd = -1;
    status_t err = dequeueBuffer(&out, &fenceFd);  //從 GraphicBufferProduce 中 拿出來(lái)一個(gè) buffer 
    
    if (err == NO_ERROR) {
        sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));//放到backBuffer中
        const Rect bounds(backBuffer->width, backBuffer->height);
 
        .......
 
        void* vaddr;
        status_t res = backBuffer->lockAsync(//把buffer的handle中的地址傳到vaddr中
                GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
                newDirtyRegion.bounds(), &vaddr, fenceFd);
 
        if (res != 0) {
            err = INVALID_OPERATION;
        } else {
            mLockedBuffer = backBuffer;
            outBuffer->width  = backBuffer->width;
            outBuffer->height = backBuffer->height;
            outBuffer->stride = backBuffer->stride;
            outBuffer->format = backBuffer->format;
            outBuffer->bits   = vaddr;//buffer地址
        }


    return err // 返回GraphicBuffer
}

int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {

    ...
    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight,
                                                            reqFormat, reqUsage, &mBufferAge,
                                                            enableFrameTimestamps ? &frameTimestamps
                                                                                  : nullptr);
                                                                                  
                                                                        
     if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
        result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);//根據(jù)需要拿到buffer
    }

    sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
    *buffer = gbuf.get();
    
    return OK;                                                                            
                                                                                                                                    
}

View繪制

View.draw

執(zhí)行View的繪制流程
下面看常見(jiàn)的 canvas.drawRect

public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) {
   native_drawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
}

android_graphics_Canvas.cpp


static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
                     jfloat right, jfloat bottom, jlong paintHandle) {
    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
    get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);

}

SkiaCanvas.drawRect

執(zhí)行Skia庫(kù)的繪制方法

void SkiaCanvas::drawRect(float left, float top, float right, float bottom,
        const SkPaint& paint) {
    mCanvas->drawRectCoords(left, top, right, bottom, paint);
 
}

SkCanvas.drawRectCoords

執(zhí)行 到SkBitmap寫(xiě)入Buffer數(shù)據(jù)


void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
                              SkScalar right, SkScalar bottom,
                              const SkPaint& paint) {
    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
    SkRect  r;
 
    r.set(left, top, right, bottom);
    this->drawRect(r, paint);

}


void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
                        const SkRect& r, SkScalar textSize) {
    if (paint.getStyle() == SkPaint::kFill_Style) {
        // fDevice 即SKBitmap 拱撵,從而實(shí)現(xiàn)將數(shù)據(jù)寫(xiě)入buffer
        draw.fDevice->drawRect(draw, r, paint);
    } else {
        SkPaint p(paint);
        p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
        draw.fDevice->drawRect(draw, r, p);
    }

}

View繪制完成后通知刷新

Surface.unlockCanvasAndPost(canvas)

public void unlockCanvasAndPost(Canvas canvas) {
   synchronized (mLock) {
       checkNotReleasedLocked();

       if (mHwuiContext != null) {
           mHwuiContext.unlockAndPost(canvas);
       } else {
            // 走軟件繪制流程
           unlockSwCanvasAndPost(canvas);
       }
   }
}

android_view.Surface.nativeUnlockCanvasAndPost

設(shè)置一個(gè)空的SkBitmap
然后執(zhí)行Surface的unlockANdPost函數(shù)

private void unlockSwCanvasAndPost(Canvas canvas) {
   if (canvas != mCanvas) {
       throw new IllegalArgumentException("canvas object must be the same instance that "
               + "was previously returned by lockCanvas");
   }
   if (mNativeObject != mLockedObject) {
       Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
               Long.toHexString(mNativeObject) + ") != mLockedObject (0x" +
               Long.toHexString(mLockedObject) +")");
   }
   if (mLockedObject == 0) {
       throw new IllegalStateException("Surface was not locked");
   }
   try {
       nativeUnlockCanvasAndPost(mLockedObject, canvas);
   } finally {
       nativeRelease(mLockedObject);
       mLockedObject = 0;
   }
}

Surface.cpp.unlockAndPost

解除buffer鎖定辉川,執(zhí)行queueBuffer最后執(zhí)行到GraphicBufferProducer的queueBuffer函數(shù),將buffer清除

status_t Surface::unlockAndPost()

{
   
    int fd = -1;
    status_t err = mLockedBuffer->unlockAsync(&fd);//通過(guò)Gralloc模塊拴测,最后是操作的ioctl
     
    err = queueBuffer(mLockedBuffer.get(), fd);
 
    mPostedBuffer = mLockedBuffer;
    mLockedBuffer = 0;
    return err;

}

Surface.queueBuffer

int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
    ...
    // 獲取Slot數(shù)組保存的buffer
    int i = getSlotFromBufferLocked(buffer); 
    ..
    IGraphicBufferProducer::QueueBufferOutput output;
    IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
            static_cast<android_dataspace>(mDataSpace), crop, mScalingMode,
            mTransform ^ mStickyTransform, fence, mStickyTransform,
            mEnableFrameTimestamps);
    ...
    // 插入buffer
    status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); 
    ...
    // 通知
    mQueueBufferCondition.broadcast();
    return err;
}

// mSlog集合為按照順序保存GraphicBuffer的數(shù)組
int Surface::getSlotFromBufferLocked(android_native_buffer_t* buffer) const {
    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
        if (mSlots[i].buffer != NULL && mSlots[i].buffer->handle == buffer->handle) {
            return i;
        }
    }
    return BAD_VALUE;
}

BufferQueueProducer.cpp.queueBuffer

根據(jù)輸入?yún)?shù)完善一個(gè)BufferItem乓旗,然后通知frameAvailabel

status_t BufferQueueProducer::queueBuffer(int slot, const QueueBufferInput &input, QueueBufferOutput *output) { 

    //從input中獲取一些列參數(shù)
    input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace,
        &crop, &scalingMode, &transform, &acquireFence, &stickyTransform,
        &getFrameTimestamps);


    sp<IConsumerListener> frameAvailableListener;
    sp<IConsumerListener> frameReplacedListener;
    BufferItem item; //一個(gè)待渲染的幀

    ...
    //item的一系列賦值操作

    item.mAcquireCalled = mSlots[slot].mAcquireCalled; 
    item.mGraphicBuffer = mSlots[slot].mGraphicBuffer; //根據(jù)slot獲取GraphicBuffer。
    item.mCrop = crop;
    item.mTransform = transform &
            ~static_cast<uint32_t>(NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
    item.mTransformToDisplayInverse =
            (transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
    item.mScalingMode = static_cast<uint32_t>(scalingMode);
    item.mTimestamp = requestedPresentTimestamp;
    item.mIsAutoTimestamp = isAutoTimestamp;
    
    ...

    if (frameAvailableListener != NULL) {
        frameAvailableListener->onFrameAvailable(item); //item是一個(gè)frame集索,準(zhǔn)備完畢屿愚,要通知外界
    } else if (frameReplacedListener != NULL) {
        frameReplacedListener->onFrameReplaced(item);
    }

    addAndGetFrameTimestamps(&newFrameEventsEntry,etFrameTimestamps ? &output->frameTimestamps : nullptr);

    return NO_ERROR;
}

BufferLayer.cpp

void BufferLayer::onFrameAvailable(const BufferItem& item) {
    ...
    mFlinger->signalLayerUpdate();
}

SurfaceFlinger.cpp

執(zhí)行SurfaceFlinger的invalidate方法

void SurfaceFlinger::signalLayerUpdate() {
    mEventQueue->invalidate();
}

————————————————————————————————————
推薦閱讀圖形系統(tǒng)總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市务荆,隨后出現(xiàn)的幾起案子妆距,更是在濱河造成了極大的恐慌,老刑警劉巖蛹含,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件毅厚,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡浦箱,警方通過(guò)查閱死者的電腦和手機(jī)吸耿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)酷窥,“玉大人咽安,你說(shuō)我怎么就攤上這事∨钔疲” “怎么了妆棒?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)沸伏。 經(jīng)常有香客問(wèn)我糕珊,道長(zhǎng),這世上最難降的妖魔是什么毅糟? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任红选,我火速辦了婚禮,結(jié)果婚禮上姆另,老公的妹妹穿的比我還像新娘喇肋。我一直安慰自己坟乾,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布蝶防。 她就那樣靜靜地躺著甚侣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪间学。 梳的紋絲不亂的頭發(fā)上殷费,一...
    開(kāi)封第一講書(shū)人閱讀 52,255評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音菱鸥,去河邊找鬼宗兼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛氮采,可吹牛的內(nèi)容都是我干的殷绍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鹊漠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼主到!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起躯概,我...
    開(kāi)封第一講書(shū)人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤登钥,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后娶靡,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體牧牢,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年姿锭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了塔鳍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡呻此,死狀恐怖轮纫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情焚鲜,我是刑警寧澤掌唾,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站忿磅,受9級(jí)特大地震影響糯彬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜葱她,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一情连、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧览效,春花似錦却舀、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至但校,卻和暖如春螃诅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背状囱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工术裸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人亭枷。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓袭艺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親叨粘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子猾编,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容