1.Surface.lockCanvas
draw(Canvas canvas)
与View组件打交道的是Canvas而不是Surface,但是应用进程与SurfaceFlinger的数据中介并不是Canvas而是Surface,这就不可避免的产生了一个问题:Canvas和Surface之间如何协作?ViewRootImpl中取得一个Canvas的方法如下:
canvas = mSurface.lockCanvas(dirty);
1.1 lockCanvas
public Canvas lockCanvas(Rect inOutDirty)throws Surface.OutOfResourcesException, IllegalArgumentException {
synchronized (mLock) {
checkNotReleasedLocked();
if (mLockedObject != 0) {
throw new IllegalStateException("Surface was already locked");
}
mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
return mCanvas;
}
}
private static native int nativeLockCanvas(int nativeObject, Canvas canvas, Rect dirty)
throws OutOfResourcesException;
1.2 nativeLockCanvas
//clazz对应java层的Surface
static jint nativeLockCanvas(JNIEnv* env, jclass clazz,
jint nativeObject, jobject canvasObj, jobject dirtyRectObj) {
//nativeObject对应C++层的Surface
sp surface(reinterpret_cast(nativeObject));
//计算dirtyRegion
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;
}
ANativeWindow_Buffer outBuffer;//用于存储UI数据的Buffer
//通过lock方法为outBuffer赋值
status_t err = surface->lock(&outBuffer, dirtyRectPtr);
SkBitmap bitmap;
ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
bitmap.setConfig(convertPixelFormat(outBuffer.format), outBuffer.width, outBuffer.height, bpr);
if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) {
bitmap.setIsOpaque(true);
}
if (outBuffer.width > 0 && outBuffer.height > 0) {
bitmap.setPixels(outBuffer.bits);//为Bitmap分配可用的数据空间
} else {
bitmap.setPixels(NULL);
}
//通过bitmap构造本地canvas对象
SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
//将本地canvas对象保存到java层canvas的数据成员变量中
swapCanvasPtr(env, canvasObj, nativeCanvas);
sp lockedSurface(surface);
lockedSurface->incStrong(&sRefBaseOwner);
return (int) lockedSurface.get();
}
1.3
status_t Surface::lock(
ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
if (mLockedBuffer != 0) {
ALOGE("Surface::lock failed, already locked");
return INVALID_OPERATION;
}
if (!mConnectedToCpu) {//step2判断是否已经建立必要的链接
int err = Surface::connect(NATIVE_WINDOW_API_CPU);
//设置内存块的用法
setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
}
ANativeWindowBuffer* out;
int fenceFd = -1;
//step5:buffer队列中dequeue一个可用的buffer
status_t err = dequeueBuffer(&out, &fenceFd);
if (err == NO_ERROR) {
//当前要处理的buffer
sp backBuffer(GraphicBuffer::getSelf(out));
sp fence(new Fence(fenceFd));
err = fence->waitForever("Surface::lock");
const Rect bounds(backBuffer->width, backBuffer->height);
Region newDirtyRegion;
//上一个buffer
const sp& frontBuffer(mPostedBuffer);
//是否可以从上一次操作中直接copy数据
const bool canCopyBack = (frontBuffer != 0 &&
backBuffer->width == frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
backBuffer->format == frontBuffer->format);
if (canCopyBack) {
//计算可以从上一次的buffer中copy多少数据
const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
if (!copyback.isEmpty())
copyBlt(backBuffer, frontBuffer, copyback);
} else {
newDirtyRegion.set(bounds);
mDirtyRegion.clear();
for (size_t i=0 ; ilock(
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
newDirtyRegion.bounds(), &vaddr);
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;
}
}
return err;
}
当前被lock的buffer最多只能有一个,以mLockedBuffer来表示,这是一个GraphicBuffer类型的强指针变量,每次lock成功之后,它就会被赋值为当前被lock的buffer,而当UI绘图结束并调用unlockAndPost时,这个mLockedBuffer会被清空且另一个变量mPostedBuffer用于记录最近一次post操作,因此在函数的开始需要判断mLockedBuffer是否为空,如果不是就要避免再次锁定一次buffer,直接返回错误。
1.4 native_window.h
typedef struct ANativeWindow_Buffer {
// 宽度,以像素为单位
int32_t width;
// 高度,以像素为单位
int32_t height;
//内存中buffer每一行所占的像素值
int32_t stride;
// 缓冲区格式
int32_t format;
//存储数据的地方
void* bits;
// 保留
uint32_t reserved[6];
} ANativeWindow_Buffer;
2.unlockCanvasAndPost
UI绘图完成后,程序需要将这幅画解锁,并提交给SurfaceFlinger进行渲染,在performDraw完成之后,用unlockCanvasAndPost接口来告知Surface一个完整的绘图操作已经完成。
2.1 nativeUnlockCanvasAndPost
static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
jint nativeObject, jobject canvasObj) {
sp surface(reinterpret_cast(nativeObject));
// detach the canvas from the surface
SkCanvas* nativeCanvas = SkNEW(SkCanvas);
swapCanvasPtr(env, canvasObj, nativeCanvas);
status_t err = surface->unlockAndPost();
}
2.2 unlockAndPost
status_t Surface::unlockAndPost()
{
if (mLockedBuffer == 0) { //当前是否有可用的buffer
return INVALID_OPERATION;
}
//buffer解除锁定
status_t err = mLockedBuffer->unlock();
//buffer入队
err = queueBuffer(mLockedBuffer.get(), -1);
//用变量mPostedBuffer记录刚刚操作过的buffer
mPostedBuffer = mLockedBuffer;
mLockedBuffer = 0;//mLockedBuffer清空,保证下一次lock的时候可以正常执行
return err;
}