之前在这篇博客中http://blog.csdn.net/kc58236582/article/details/52437855我们分析过应用在ViewRootImpl的drawSoftware函数中完成绘制
下面我们来看下这个函数,它先调用了Surface的lockCanvas获取一个Canvas,然后再调用surface.unlockCanvasAndPost来表示绘制结束。
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty) { // Draw with software renderer. final Canvas canvas; try { final int left = dirty.left; final int top = dirty.top; final int right = dirty.right; final int bottom = dirty.bottom; canvas = mSurface.lockCanvas(dirty);//获取一个Canvas ...... finally { try { surface.unlockCanvasAndPost(canvas);//绘制结束 } catch (IllegalArgumentException e) { Log.e(TAG, "Could not unlock surface", e); mLayoutRequested = true; // ask wm for a new surface next time. //noinspection ReturnInsideFinallyBlock return false; } if (LOCAL_LOGV) { Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost"); } } return true; }
一、应用进程申请buffer
我们先来看Surface的lockCanvas函数,其调用了native函数nativeLockCanvas
public Canvas lockCanvas(Rect inOutDirty) throws Surface.OutOfResourcesException, IllegalArgumentException { synchronized (mLock) { checkNotReleasedLocked(); if (mLockedObject != 0) { // Ideally, nativeLockCanvas() would throw in this situation and prevent the // double-lock, but that won't happen if mNativeObject was updated. We can't // abandon the old mLockedObject because it might still be in use, so instead // we just refuse to re-lock the Surface. throw new IllegalArgumentException("Surface was already locked"); } mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty); return mCanvas; } }
这个函数在android_view_Surface.cpp中,这个函数内容很多,我们先调用了Surface的lock函数来申请buffer,然后新建了一个SkBitmap,设置了内存地址,并且把这个bitmap放入了Canvas中。
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) { sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject)); if (!isSurfaceValid(surface)) { doThrowIAE(env); return 0; } 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; status_t err = surface->lock(&outBuffer, dirtyRectPtr);//从SurfaceFlinger中申请内存buffer if (err < 0) { const char* const exception = (err == NO_MEMORY) ? OutOfResourcesException : "java/lang/IllegalArgumentException"; jniThrowException(env, exception, NULL); return 0; } SkImageInfo info = SkImageInfo::Make(outBuffer.width, outBuffer.height, convertPixelFormat(outBuffer.format), kPremul_SkAlphaType); if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) { info.fAlphaType = kOpaque_SkAlphaType; } 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);//bitmap设置其内存地址 } else { // be safe with an empty bitmap. bitmap.setPixels(NULL); } Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj); nativeCanvas->setBitmap(bitmap);//设置Canvas的bitmap 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的lock函数,先是调用了dequeueBuffer来申请内存,然后放入backBuffer。后面调用GraphicBuffer的lockAsync来把Buffer中的handle的地址放到vaddr中,最后把vaddr放到outBuffer的bits中。
status_t Surface::lock( ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) { ...... ANativeWindowBuffer* out; int fenceFd = -1; status_t err = dequeueBuffer(&out, &fenceFd);//申请内存 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); ALOGW_IF(res, "failed locking buffer (handle = %p)", backBuffer->handle); 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; }
1.1 申请buffer
Surface的dequeueBuffer函数主要就是从SurfaceFlinger中申请buffer。
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { ATRACE_CALL(); ALOGV("Surface::dequeueBuffer"); uint32_t reqWidth; uint32_t reqHeight; bool swapIntervalZero; PixelFormat reqFormat; uint32_t reqUsage; ...... int buf = -1; sp<Fence> fence; status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero,//在SurfaceFlinger中申请内存,只要返回mSlots中的序号 reqWidth, reqHeight, reqFormat, reqUsage); Mutex::Autolock lock(mMutex); sp<GraphicBuffer>& gbuf(mSlots[buf].buffer); if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) { freeAllBuffers(); } if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);//根据需要拿到buffer ...... } ...... *buffer = gbuf.get(); return OK; }
下面我们再看下SurfaceFlinger中对应的dequeueBuffer和requestBuffer函数。
我们先看BufferQueueProducer.cpp中dequeueBuffer关于分配buffer的一段代码:
...... if (returnFlags & BUFFER_NEEDS_REALLOCATION) {//需要分配内存 status_t error; BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot); sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer( width, height, format, usage, &error)); if (graphicBuffer == NULL) { BQ_LOGE("dequeueBuffer: createGraphicBuffer failed"); return error; } { // Autolock scope Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned"); return NO_INIT; } graphicBuffer->setGenerationNumber(mCore->mGenerationNumber); mSlots[*outSlot].mGraphicBuffer = graphicBuffer;//将分配的内存放到mSlots中,outSlot就是给应用进程mSlots的序号 } // Autolock scope } ....... return returnFlags;
然后我们再来看其requestBuffer函数,就是根据序号,从mSlots拿到buffer。
status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { ATRACE_CALL(); BQ_LOGV("requestBuffer: slot %d", slot); Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { BQ_LOGE("requestBuffer: BufferQueue has been abandoned"); return NO_INIT; } if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { BQ_LOGE("requestBuffer: slot index %d out of range [0, %d)", slot, BufferQueueDefs::NUM_BUFFER_SLOTS); return BAD_VALUE; } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { BQ_LOGE("requestBuffer: slot %d is not owned by the producer " "(state = %d)", slot, mSlots[slot].mBufferState); return BAD_VALUE; } mSlots[slot].mRequestBufferCalled = true; *buf = mSlots[slot].mGraphicBuffer; return NO_ERROR; }
1.2 将buffer的地址放到vaddr中
我们继续分析Surface的lock函数,来看下GraphicBuffer的lockAsyc,其调用了getBufferMapper().lockAsync,而这个getBufferMapper返回的是GraphicBufferMapper
status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, int fenceFd) { if (rect.left < 0 || rect.right > width || rect.top < 0 || rect.bottom > height) { ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", rect.left, rect.top, rect.right, rect.bottom, width, height); return BAD_VALUE; } status_t res = getBufferMapper().lockAsync(handle, inUsage, rect, vaddr, fenceFd); return res; }
这里的GraphicBufferMapper::lockAsync调用的是mAllocMod的lock函数
status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd) { ATRACE_CALL(); status_t err; if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3) { err = mAllocMod->lockAsync(mAllocMod, handle, static_cast<int>(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr, fenceFd); } else { if (fenceFd >= 0) { sync_wait(fenceFd, -1); close(fenceFd); } err = mAllocMod->lock(mAllocMod, handle, static_cast<int>(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr); } ALOGW_IF(err, "lockAsync(...) failed %d (%s)", err, strerror(-err)); return err; }mAllocMod也是Gralloc模块。
GraphicBufferMapper::GraphicBufferMapper() : mAllocMod(0) { hw_module_t const* module; int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID); if (err == 0) { mAllocMod = reinterpret_cast<gralloc_module_t const *>(module); } }
最后我们来看下Gralloc模块的lock函数,其实也就是将handle的base(buffer地址)放到vaddr中。
static int gralloc_lock(gralloc_module_t const* module, buffer_handle_t handle, int usage, int l, int t, int w, int h, void** vaddr) { if (private_handle_t::validate(handle) < 0) { AERR("Locking invalid buffer %p, returning error", handle ); return -EINVAL; } private_handle_t* hnd = (private_handle_t*)handle; if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_UMP || hnd->flags & private_handle_t::PRIV_FLAGS_USES_ION) { hnd->writeOwner = usage & GRALLOC_USAGE_SW_WRITE_MASK; } if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) { *vaddr = (void*)hnd->base;//将handle的base(buffer地址)放到vaddr中 } return 0; }
1.3 Canvas的获取
这样我们再回过头来看nativeLockCanvas函数,buffer也申请了,buffer地址也放到了Canvas的SkBitmap中了(意味着写到canvas,可以写到buffer的地址中了)。最后我们再来看Canvas的获取。
在nativeLockCanvas中通过GraphicsJNI::getNativeCanvas来获取到canvasObj,这个就是上层在ViewRootImpl的Canvas的对象。
Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
我们来看下这个函数,这个就是获取java层。
android::Canvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) { SkASSERT(env); SkASSERT(canvas); SkASSERT(env->IsInstanceOf(canvas, gCanvas_class)); jlong canvasHandle = env->GetLongField(canvas, gCanvas_nativeInstanceID); if (!canvasHandle) { return NULL; } return reinterpret_cast<android::Canvas*>(canvasHandle); }
最后通过如下没我们发现是Canvas的mNativeCanvasWrapper对象。
gCanvas_class = make_globalref(env, "android/graphics/Canvas"); gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvasWrapper", "J");
而在Canvas中如果是通过mNativeCanvasWrapper复制Canvas对象,使用如下构造函数。
public Canvas(long nativeCanvas) { if (nativeCanvas == 0) { throw new IllegalStateException(); } mNativeCanvasWrapper = nativeCanvas; mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper); mDensity = Bitmap.getDefaultDensity(); }
那么必然会有一个地方创建了Canvas对象,最后我们发现会在View中创建Canvas.
...... Canvas canvas; if (attachInfo != null) { canvas = attachInfo.mCanvas; if (canvas == null) { canvas = new Canvas(); } canvas.setBitmap(bitmap); ......
最后都是通过SkBitmap来写数据到buffer中去。
二、应用进程绘制
绘制的话,我们举个简单的例子canvas.drawRect
public void drawRect(@NonNull RectF rect, @NonNull Paint paint) { native_drawRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, paint.getNativeInstance()); }我们来看下native_drawRect函数
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的drawRectCoords
void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) { mCanvas->drawRectCoords(left, top, right, bottom, paint); }SkCanvas的drawRectCoords
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); }SkCanvas::DrawRect函数,这里的fDevice就是SkBitmap。
void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, const SkRect& r, SkScalar textSize) { if (paint.getStyle() == SkPaint::kFill_Style) { draw.fDevice->drawRect(draw, r, paint); } else { SkPaint p(paint); p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); draw.fDevice->drawRect(draw, r, p); } }SkBitmap之前我们把buffer的地址传进去了,这样就可以将数据写入buffer了。
三、绘制完成
在ViewRootImpl中绘制完成后,最后会调用surface.unlockCanvasAndPost(canvas)
public void unlockCanvasAndPost(Canvas canvas) { synchronized (mLock) { checkNotReleasedLocked(); if (mHwuiContext != null) { mHwuiContext.unlockAndPost(canvas); } else { unlockSwCanvasAndPost(canvas); } } }
正常是调用unlockSwCanvasAndPost函数,这个函数主要是调用了nativeUnlockCanvasAndPost native函数。
这里仙剑SkBitmap重新设置了一个空的,然后调用了surface的unlockAndPost函数
static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj) { sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject)); if (!isSurfaceValid(surface)) { return; } // 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); } }
下面我们主要看下queueBuffer函数
status_t Surface::unlockAndPost() { if (mLockedBuffer == 0) { ALOGE("Surface::unlockAndPost failed, no locked buffer"); return INVALID_OPERATION; } int fd = -1; status_t err = mLockedBuffer->unlockAsync(&fd);//通过Gralloc模块,最后是操作的ioctl 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; }
在Surface的queueBuffer函数中调用了如下函数
mGraphicBufferProducer->queueBuffer
这个函数最终会将BufferItem的buffer清除,通知消费者的onFrameAvailable接口。然后消费者可以根据mSlots的序号再来拿buffer。
item.mGraphicBuffer.clear(); item.mSlot = BufferItem::INVALID_BUFFER_SLOT; // Call back without the main BufferQueue lock held, but with the callback // lock held so we can ensure that callbacks occur in order { Mutex::Autolock lock(mCallbackMutex); while (callbackTicket != mCurrentCallbackTicket) { mCallbackCondition.wait(mCallbackMutex); } if (frameAvailableListener != NULL) { frameAvailableListener->onFrameAvailable(item); } else if (frameReplacedListener != NULL) { frameReplacedListener->onFrameReplaced(item); } ++mCurrentCallbackTicket; mCallbackCondition.broadcast(); }