之前在博客中我们分析过应用在ViewRootImpl的drawSoftware函数中完成绘制。当然这里只是针对软件绘制,是在draw函数中,调用的drawSoftware,使用的是skia库绘制二维的,如果是一些三维的必须使用硬件绘制(后续会分析)。
下面我们来看下这个函数,它先调用了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();
}
















