本文内容接着上一篇文章Android的UI显示原理之Surface的创建继续来看Surface渲染的大致过程。

对于Surface的渲染可以转化为ViewRootImpl的渲染。因此我们从ViewRootImpl.draw()来看一下它的渲染逻辑。这个方法最终会调用到ViewRootImpl.drawSoftward():

private boolean drawSoftware(Surface surface, AttachInfo attachInfo,...) {    // Draw with software renderer.    final Canvas canvas;    ...    canvas = mSurface.lockCanvas(dirty);  //step 1    ...    mView.draw(canvas);  //setp 2    ...    mSurface.unlockCanvasAndPost(canvas);  //step 3}

mViewViewRootImpl的根ViewmSurface即为上一篇文章分析的所创建的Surface,它的实际对象在nativie层。

上面3步大致描绘了ViewRootImpl的绘制原理,本文就逐一分析这3步,来大致了解ViewRootImpl的渲染逻辑。

mSurface.lockCanvas()

public Canvas lockCanvas(Rect inOutDirty){    ...    mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);    return mCanvas;}

这个方法会直接调用到native方法nativeLockCanvas(mNativeObject, mCanvas, inOutDirty)

mNativeObject就是Surface创建时对应的nativeSurface指针,inOutDirty指明了lock的区域。

android_view_Surface.cpp

static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {    sp surface(reinterpret_cast(nativeObject)); //转换指针    ...    Rect dirtyRect(Rect::EMPTY_RECT);    Rect* dirtyRectPtr = NULL;    //获取 lock 区域    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;    }    ANativeWindow_Buffer outBuffer;    status_t err = surface->lock(&outBuffer, dirtyRectPtr);    ...    sp lockedSurface(surface);    return (jlong) lockedSurface.get(); //返回surface指针}

这个方法主要新建了一个Rect对象,确定要lock的区域的参数,然后调用surface->lock(&outBuffer, dirtyRectPtr):

Surface.cpp

status_t Surface::lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds){    ANativeWindowBuffer* out; int fenceFd = -1;    status_t err = dequeueBuffer(&out, &fenceFd);  //从 GraphicBufferProduce 中 拿出来一个 buffer     sp backBuffer(GraphicBuffer::getSelf(out));  // 构建一个 backbuffer    status_t res = backBuffer->lockAsync(...);}

可以看出lock方法,首先通过dequeueBuffer来获取一个ANativeWindowBuffer,然后利用它构造一个GraphicBuffer,它被称为backBuffer,然后调用它的backBuffer->lockAsync(...),那么怎么获取一个ANativeWindowBuffer呢?

dequeueBuffer()

Surface.cpp

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);    ...经过一系列的操作,buffer最终会指向&buf}

我们上一篇文章中已经介绍过了GraphicBufferProducer,它是一个Layergraphic buffer producerLayer在绘制时,会从GraphicBufferProducer取出一个GraphicBuffer来绘制。所以可以理解为GraphicBufferProducer存放着一个Layer待绘制的一帧。dequeueBuffer()所做的事情就是:从GraphicBufferProducer取出一个GraphicBuffer

至于backBuffer->lockAsync(...)所做的操作就不细看了,可以猜想就是把这个GraphicBuffer锁上,保证一个GraphicBuffer绘制操作的不可重入。

综上,surface.lockCanvas()的主要逻辑可以使用下面这张图来表示:

SurfaceLockCanvas.png

mSurface.lockCanvas最终是lock了一个GraphicBuffer。继续看mView.draw(canvas):

mView.draw(canvas)

View.draw(canvas)所做的事情其实就是:根据View的状态来把带绘制的数据保存到Canvas。对Canvas我们到最后再来看一下它和Surface的关系。

mSurface.unlockCanvasAndPost(canvas)

canvas的绘制数据准备ok后,Surface就可以开始绘制了,而绘制操作的发起点就是Surface.unlockCanvasAndPost()方法,这个方法会调用到:

private void unlockSwCanvasAndPost(Canvas canvas) {    ...    try {        nativeUnlockCanvasAndPost(mLockedObject, canvas); //mLockedObject其实就是native的那个surface    } finally {        nativeRelease(mLockedObject);        mLockedObject = 0;    }}

继续看nativeUnlockCanvasAndPost()

android_view_Surface.cpp

static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,jlong nativeObject, jobject canvasObj) {     sp surface(reinterpret_cast(nativeObject));    ...    // detach the canvas from the surface    Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);  // 把java canvas指针转化为native 指针    nativeCanvas->setBitmap(SkBitmap());    // unlock surface    status_t err = surface->unlockAndPost();}

即调用了surface->unlockAndPost():

Surface.cpp

status_t Surface::unlockAndPost(){    ...    int fd = -1;    status_t err = mLockedBuffer->unlockAsync(&fd);    err = queueBuffer(mLockedBuffer.get(), fd);    mPostedBuffer = mLockedBuffer;    mLockedBuffer = 0;    return err;}

这里mLockedBuffer其实就是前面的backBuffermLockedBuffer->unlockAsync(&fd)的操作其实很简单,就是解除GraphicBuffer的lock状态,主要看一下queueBuffer(mLockedBuffer.get(), fd)

Surface.cpp

int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {    ...    int i = getSlotFromBufferLocked(buffer);     ...    IGraphicBufferProducer::QueueBufferOutput output;    IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,            static_cast(mDataSpace), crop, mScalingMode,            mTransform ^ mStickyTransform, fence, mStickyTransform,            mEnableFrameTimestamps);    ...    status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);     ...    mQueueBufferCondition.broadcast();    return err;}

对于inputoutput这里先不做细追,我猜测input中应该包含绘制的数据。但getSlotFromBufferLocked(buffer)是干什么的呢?它其实就是获取真正的GraphicBuffer的在mSlots集合中真正的index:

Surface.cpp

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

对于mSlots集合,可以认为他就是按顺序保存GraphicBuffer的数组即可:

Surface.h

    // mSlots stores the buffers that have been allocated for each buffer slot.    // It is initialized to null pointers, and gets filled in with the result of    // IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a    // slot that has not yet been used. The buffer allocated to a slot will also    // be replaced if the requested buffer usage or geometry differs from that    // of the buffer allocated to a slot.    BufferSlot mSlots[NUM_BUFFER_SLOTS];

继续看mGraphicBufferProducer->queueBuffer(i, input, &output), 通过上一篇文章已经知道mGraphicBufferProducerBufferQueueProducer的实例:

BufferQueueProducer.cpp

status_t BufferQueueProducer::queueBuffer(int slot, const QueueBufferInput &input, QueueBufferOutput *output) {     //从input中获取一些列参数    input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace,        &crop, &scalingMode, &transform, &acquireFence, &stickyTransform,        &getFrameTimestamps);    sp frameAvailableListener;    sp frameReplacedListener;    BufferItem item; //可以理解为一个待渲染的帧    ...下面就是对item的一系列赋值操作    item.mAcquireCalled = mSlots[slot].mAcquireCalled;     item.mGraphicBuffer = mSlots[slot].mGraphicBuffer; //根据slot获取GraphicBuffer。    item.mCrop = crop;    item.mTransform = transform &            ~static_cast(NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);    item.mTransformToDisplayInverse =            (transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;    item.mScalingMode = static_cast(scalingMode);    item.mTimestamp = requestedPresentTimestamp;    item.mIsAutoTimestamp = isAutoTimestamp;        ...    if (frameAvailableListener != NULL) {        frameAvailableListener->onFrameAvailable(item); //item是一个frame,准备完毕,要通知外界    } else if (frameReplacedListener != NULL) {        frameReplacedListener->onFrameReplaced(item);    }    addAndGetFrameTimestamps(&newFrameEventsEntry,etFrameTimestamps ? &output->frameTimestamps : nullptr);    return NO_ERROR;}

其实从queueBuffer()可以看出,mGraphicBufferProducer中存放的都是可以被渲染的GraphicBuffer,这个buffer可能被渲染完毕,也可能处于待渲染状态。

queueBuffer的主要操作是根据输入参数完善一个BufferItem,然后通知外界去绘制这个BufferItem。这里这个frameAvailableListener是什么呢?有兴趣的同学可以去跟一下, 不过最终回到BufferLayer.onFrameAvailable():

BufferLayer.cpp

// ---------------------------------------------------------------------------// Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener// ---------------------------------------------------------------------------void BufferLayer::onFrameAvailable(const BufferItem& item) {    ...    mFlinger->signalLayerUpdate();}

这个方法直接调用了mFlinger->signalLayerUpdate(),看样是要让SurfaceFlinger来渲染了:

SurfaceFlinger.cpp

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

至于SurfaceFlinger是如何渲染的,本文就不继续追踪了。用下面这张图总结一下mSurface.unlockCanvasAndPost(canvas):

SurfaceUnlockCanvasAndPost(canvas).png

Canvas与Surface

Canvas是一个绘图的工具类,其API提供了一系列绘图指令供开发者使用。根据绘制加速模式的不同,Canvas有软件Canvas与硬件Canvas只分。Canvas的绘图指令可以分为两个部分:

  • 绘制指令:这些最常用的指令由一系列名为drawXXX的方法提供。他们用来实现实际的绘制行为,例如绘制点、线、圆以及方块等。
  • 辅助指令:这些用于提供辅助功能的指令将会影响后续绘制指令的效果,如设置变换、裁剪区域等。Canvas还提供了saveresotore用于撤销一部分辅助指令的效果。

对于软件Canvas来说,其绘制目标是一个位图Bitmap。在Surface.unlockAndPost时,这个Bitmap所描述的内容会反映到SurfaceBuffer中。可以用下面这张图来表示:

Canvas与Surface.png

最后:

欢迎关注我的Android进阶计划看更多干货

欢迎关注我的微信公众号:susion随心

微信公众号.jpeg

更多相关文章

  1. Android(安卓)自定义View实现带进度的下载按钮
  2. Android通过自定义View实现心形(贝塞尔曲线)
  3. 一步一步学android OpenGL ES2.0编程(1)
  4. Android(安卓)开发之RecyclerView的使用
  5. Android(安卓)自定义View视图
  6. Android(安卓)opengl es 2.0怎么学习
  7. Android(安卓)渐变 -- Shader
  8. 【UI交互效果】android UI效果二: 给选中的图片加边框
  9. Android使用Canvas绘制圆形进度条效果

随机推荐

  1. Android中遍历文件夹、比较文件类型测试
  2. android 触摸手指动作放大和缩小图片
  3. android全屏显示
  4. Android实现文件上传功能
  5. Android(安卓)全屏
  6. android开机动画bootanimation
  7. 提示Android(安卓)dependency 'com.andro
  8. 选择框在右边的单选按钮。。
  9. android 通知Notification的使用小实例(振
  10. Android(安卓)简单视频播放器(破烂版,后续