源码:8.x系统

我们知道ViewRootImpl是处理绘制流程的地方,具体分析如下:

ViewRootImpl.java

private void performTraversals() {

······

performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

······

performLayout(lp, mWidth, mHeight);

······

performDraw();

······

}

测量、布局、绘制,我们重点看绘制performDraw

private void performDraw() {

······

draw(fullRedrawNeeded);

······

}

private void draw(boolean fullRedrawNeeded) {

······

if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {

if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {

······//硬件加速

} else {

·····

//drawSoftware为软件加速

if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)){

······

}

}

}

}

private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,

boolean scalingRequired, Rect dirty) {

······

canvas = mSurface.lockCanvas(dirty);

······

mView.draw(canvas);

······

surface.unlockCanvasAndPost(canvas);

······

}

终于来到了,我们需要重点分析的地方,接下来我们重点分析:

1.mSurface.lockCanvas(dirty)

2.mView.draw(canvas)是否可以用其他的替代?

3.surface.unlockCanvasAndPost(canvas)

重点分析一:mSurface.lockCanvas(dirty)

Surface.java

public Canvas lockCanvas(Rect inOutDirty)

throws Surface.OutOfResourcesException, IllegalArgumentException {

·····

mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);

return mCanvas;

}

首先,我们重点关注点在返回值mCanvas,而mCanvas初始化的地方为private final Canvas mCanvas = new CompatibleCanvas();

,说明这个mCanvas初始化的时候是空壳。提问:canvas和surface有什么必然的关联?

其次,我们重点看nativeLockCanvas具体做了什么?

android_view_Surface.cpp

static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,

jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {

sp surface(reinterpret_cast(nativeObject));

······

//关注点1

ANativeWindow_Buffer outBuffer;

status_t err = surface->lock(&outBuffer, dirtyRectPtr);

······

//关注点2

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

}

Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);

nativeCanvas->setBitmap(bitmap);

·····

}

初步分析:

关注点1:

一个buffer跟surface绑定在一起

关注点2:

bitmap和canvas绑定在一起,而bimap和buffer绑定在一起

小结论:

surface和canvas绑定在一起,用了一个bitmap,进一步说,是一个buffer。

详细分析:

关注点1:

status_t err = surface->lock(&outBuffer, dirtyRectPtr);

Surface.cpp

status_t Surface::lock(

ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)

{

//2.backBuffer来自out,而out由dequeueBuffer函数赋值

ANativeWindowBuffer* out;

int fenceFd = -1;

status_t err = dequeueBuffer(&out, &fenceFd);

·····

sp backBuffer(GraphicBuffer::getSelf(out));

//1.逆向思维分析,outBuffer是被赋值的?

//是被backBuffer,backBuffer是怎么来的?

mLockedBuffer = backBuffer;

outBuffer->width = backBuffer->width;

outBuffer->height = backBuffer->height;

outBuffer->stride = backBuffer->stride;

outBuffer->format = backBuffer->format;

outBuffer->bits = vaddr;

}

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

······

//gbuf由mGraphicBufferProducer(GBP)产生

result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);

······

//逆向思维分析:buffer来自gbuf

*buffer = gbuf.get();

}

关注点2:

java层的canvas是一个空壳,通过native层赋予了值,如下:

nativeCanvas->setBitmap(bitmap);

所以,canvas的关键在于对这个bitmap赋予生机。

进一步小结:

surface和canvas绑定在一起,用了一个bitmap,进一步说,是一个buffer。

这个buffer是由Surface的mGraphicBufferProducer生产。

重点分析二: mView.draw(canvas)

顾明思意,canvas会把view中元素draw到自身身上。那是否可以通过其他途径来实现此意图呢?

mCanvas.drawBitmap

这种方法,就是直接赋值一张图片,简单粗暴。

例如,现在车载产品上流行的UsbCamera,在绘制usbcamera成像时,就会采用这种方法。

具体操作可以这样做:

1.SurfaceView负责展示成像

2.我们把SurfaceView中的Surface拿出来

3.之后通过Surface中的canvas.drawBitmap进行设置成像图案

因为surface可以进行跨进程传递,所以,负责展示和图像处理,可以分为两个进程执行。

这样就减小了耦合。

重点分析三:surface.unlockCanvasAndPost(canvas)

Surface.java

public void unlockCanvasAndPost(Canvas canvas) {

if (mHwuiContext != null) {//硬件绘制

mHwuiContext.unlockAndPost(canvas);

} else {//软件绘制

unlockSwCanvasAndPost(canvas);

}

}

我们关注软件绘制

private void unlockSwCanvasAndPost(Canvas canvas) {

······

try {

nativeUnlockCanvasAndPost(mLockedObject, canvas);

} finally {

······

}

······

}

android_view_Surface.cpp

static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,

jlong nativeObject, jobject canvasObj) {

······

// detach the canvas from the surface

Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);

nativeCanvas->setBitmap(SkBitmap());

// unlock surface

status_t err = surface->unlockAndPost();

if (err < 0) {

doThrowIAE(env);

}

}

这里重点处理了两块:

a.把canvas的bitmap设置为了空壳,也就是此时surface与canvas已经失去深入的关联

b.我们具体分析surface->unlockAndPost()

Surface.cpp

status_t Surface::unlockAndPost()

{

······

int fd = -1;

status_t err = mLockedBuffer->unlockAsync(&fd);

ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);

err = queueBuffer(mLockedBuffer.get(), fd);

ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",

mLockedBuffer->handle, strerror(-err));

mPostedBuffer = mLockedBuffer;

mLockedBuffer = 0;

return err;

}

这里,我们可以看到native层的Surface有两个buffer,一个是mPostedBuffer(frontBuffer),一个是mLockedBuffer(backBuffer),这两个buffer在相互切换。

也就是说,当unlock的时候,mLockedBuffer就切换到了前台,而后台的buffer就变成了0.

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

····

status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);

····

}

小结:

Surface的buffer绘制完后,通过mGraphicBufferProducer提交。

参考学习