当前位置: 首页> 科技> IT业 > 建网站要先建什么_网业游戏大全_360搜图片识图_提高搜索引擎检索效果的方法

建网站要先建什么_网业游戏大全_360搜图片识图_提高搜索引擎检索效果的方法

时间:2025/7/10 9:03:22来源:https://blog.csdn.net/boker_han/article/details/143104948 浏览次数:0次
建网站要先建什么_网业游戏大全_360搜图片识图_提高搜索引擎检索效果的方法

前言

在《浅析Android中View的测量布局流程》中分析到,VSYNC信号到达App进程之后开启了View布局过程,经过对整个View树遍历完成测量和布局,最终确定所有View的大小以及在屏幕中所处的位置。但是View的内容想要在屏幕上可见,还需要经过绘制渲染来生成图形数据并交由硬件来刷新屏幕才可以。

在《浅析Android View绘制过程中的Surface》中分析到,View绘制渲染生成的图形数据需要在进程间传输,最终才能完成合成上屏。基于跨进程的数据传输,生产者(通常是App进程)生产图形数据并交由SurfaceFlinger进程消费,而生产图形数据的实现方式经过多个Android版本迭代之后,最终分为了软件渲染和硬件渲染两种实现。从Android 3.0开始支持硬件加速,Android 4.0开始默认开启硬件加速。下面会从软件绘制和硬件绘制两种渲染机制来分析View的绘制流程。

软件渲染

软件渲染是指利用CPU对绘制命令进行处理,直接生成渲染数据并交由SurfaceFlinger进程进行合成上屏。

下面从View绘制流程的入口处分析软件绘制流程对应的源码,看下是如何将各种绘制操作转换为图形数据并用于最终的合成上屏的。

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks, AttachedSurfaceControl {// ...private void performTraversals() {// ...if (!isViewVisible) {// ...} else if (cancelAndRedraw) {// ...} else {// ...// 开始绘制if (!performDraw() && mSyncBufferCallback != null) {mSyncBufferCallback.onBufferReady(null);}}// ...}private boolean performDraw() {final boolean fullRedrawNeeded = mFullRedrawNeeded || mSyncBufferCallback != null;// ...// 软件绘制时,usingAsyncReport为falseboolean usingAsyncReport = isHardwareEnabled() && mSyncBufferCallback != null;// ...try {boolean canUseAsync = draw(fullRedrawNeeded, usingAsyncReport && mSyncBuffer);// ...} finally {// ...}// ...}private boolean draw(boolean fullRedrawNeeded, boolean forceDraw) {Surface surface = mSurface;// surface不可用时直接return,而surface在经过relayoutWindow之后已经被更新并处于可用状态if (!surface.isValid()) {return false;}// ...final Rect dirty = mDirty;if (fullRedrawNeeded) {dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));}// ...if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {if (isHardwareEnabled()) {// ...// 开启硬件绘制时,使用ThreadedRenderer进行绘制mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);} else {// ...// 未开启硬件绘制时,使用软件绘制,surface就是成员变量mSurfaceif (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty, surfaceInsets)) {return false;}}}// 如果当前正在动画,调度下一次VSYNC信号来执行布局流程if (animating) {mFullRedrawNeeded = true;scheduleTraversals();}return useAsyncReport;}private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets) {// Draw with software renderer.final Canvas canvas;// ...try {// ...// 1. 根据dirty从Surface对象中锁定一个canvas对象canvas = mSurface.lockCanvas(dirty);// ...} catch (Surface.OutOfResourcesException e) {handleOutOfResourcesException(e);return false;} catch (IllegalArgumentException e) {mLayoutRequested = true;    // ask wm for a new surface next time.return false;} finally {// ...}try {// ...// 2. 遍历绘制子ViewmView.draw(canvas);// ...} finally {try {// 3. 解锁canvas并将数据提交给SurfaceFlinger进程进行合成上屏surface.unlockCanvasAndPost(canvas);} catch (IllegalArgumentException e) {mLayoutRequested = true;    // ask wm for a new surface next time.return false;}}return true;}
}

上面的代码是软件绘制的主要流程,在关键的代码处增加了注释,可以看到对于软件绘制来说,首先从Surface中获取Canvas对象,然后利用Canvas对象在遍历子View时进行绘制命令处理,最终释放Canvas对象并将绘制数据交由SurfaceFlinger进程进行合成上屏。

因此,整个软件绘制过程可以分为:

  1. 通过Surface对象锁定/创建Canvas对象;
  2. 使用Canvas对象进行View的绘制;
  3. 使用GraphicBuffer提交图形数据给SurfaceFlinger进程;

Canvas对象的创建过程

Canvas对象内部持有了GraphicBuffer,GraphicBuffer指向的内存空间用于存储绘制指令处理后生成的数据。

我们从Surface#lockCanvas方法开始分析,Surface#lockCanvas方法内部通过nativeLockCanvas方法调用到了native层,主要工作是申请一个Buffer用于后续的绘制流程。

/*** 持有一个被屏幕合成器管理的原始buffer.* surface通常是由graphic buffer的消费者创建或者提供,比如SurfaceTexture、MediaRecorder以及Allocation,然后交由生产者比如OpenGL的EGL14#eglCreateWindowSurface、MediaPlayer的MediaPlayer#setSurface以及CameraDevice的CameraDevice#createCaptureSession进行绘制填充数据。*/
public class Surface implements Parcelable {long mNativeObject;@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)private long mLockedObject;private final Canvas mCanvas = new CompatibleCanvas();/*** 获取一个canvas对象用于将绘制数据推入这个surface对象,在绘制到提供的Canvas对象之后,必须调用unlockCanvasAndPost来将新的绘制内容提交给surface。* @param inOutDirty 希望重新绘制的矩形区域,如果需要将整个surface进行重绘,则该参数传值为null即可。* @return 一个用于将绘制数据推入这个surface对象的canvas对象.*/public Canvas lockCanvas(Rect inOutDirty) throws Surface.OutOfResourcesException, IllegalArgumentException {synchronized (mLock) {checkNotReleasedLocked();// 变量mLockedObject用于确保lockCanvas和unlockCanvasAndPost成对调用,实现同一个Surface对象下只能有一个Canvas对象正在被使用if (mLockedObject != 0) {throw new IllegalArgumentException("Surface was already locked");}// mNativeObject对应native层的surface对象// mLockedObject对应native层的surface对象// mCanvas用于映射surface对象的buffermLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);return mCanvas;}}private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty) throws OutOfResourcesException;// ...
}

从上面的代码可以看到nativeLockCanvas的入参包括了native层的Surface对象mNativeObject以及Java层的Canvas对象mCanvas以及需要刷新的矩形区域inOutDirty,结合源码看下具体的实现是什么样的。

// frameworks/base/core/jni/android_view_Surface.cpp
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {// 获取native层的Surface对象sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));// ...   // 1. 将Java层传递过来的Rect数据拷贝到native层的Rect中Rect dirtyRect(Rect::EMPTY_RECT);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;}// 2. 通过native层的Surface对象锁定一个缓冲区ANativeWindow_Buffer,缓冲区保存了Rect相关信息ANativeWindow_Buffer buffer;status_t err = surface->lock(&buffer, dirtyRectPtr);// ...// 3. 根据Java层的canvasObj创建一个native层的Canvas对象,并将上面的缓冲区设置到Canvas对象中graphics::Canvas canvas(env, canvasObj);canvas.setBuffer(&buffer, static_cast<int32_t>(surface->getBuffersDataSpace()));// 根据Java层传递的dirtyRectObj对canvas的矩形区域进行设置if (dirtyRectPtr) {canvas.clipRect({dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom});}// 4. 为native层的surface对象创建一个强引用对象lockedSurface, 并返回给Java层,用于在绘制结束之后通过JNI对native层的资源进行释放sp<Surface> lockedSurface(surface);lockedSurface->incStrong(&sRefBaseOwner);return (jlong) lockedSurface.get();
}

可以看到nativeLockCanvas方法中首先通过native层的Surface对象锁定了一个缓冲区ANativeWindowBuffer,然后将ANativeWindowBuffer设置到native层的Canvas对象中,最后将surface返回给了Java层。这里主要看下Surface::lock方法做了什么。

// frameworks/native/libs/gui/Surface.cpp
// mSlots存储了分配给每一个slot的buffer,初始化值是空指针,当client从一个没有被使用过的slot中获取buffer时,由IGraphicBufferProducer::requestBuffer返回的结果进行填充。当buffer的状态发生变化时,slot中的buffer将会被替换。
// NUM_BUFFER_SLOTS默认为64
BufferSlot mSlots[NUM_BUFFER_SLOTS];status_t Surface::lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) {// mLockedBuffer记录了最后一次lock成功的buffer,如果上次lock成功的buffer没有被释放则不用重复lockif (mLockedBuffer != nullptr) {return INVALID_OPERATION;}if (!mConnectedToCpu) {int err = Surface::connect(NATIVE_WINDOW_API_CPU);if (err) {return err;}// 从这里开始准备开始软件渲染setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);}ANativeWindowBuffer* out;int fenceFd = -1;// 1. 从BufferQueue中获取buffer以及相关的fencestatus_t err = dequeueBuffer(&out, &fenceFd);if (err == NO_ERROR) {// 将out的类型强转为GraphicBuffersp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));const Rect bounds(backBuffer->width, backBuffer->height);// ...void* vaddr;// 2. 锁定获取的GraphicBuffer,避免被其他地方使用,同时将GraphicBuffer持有的内存地址写入vaddrstatus_t res = backBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, newDirtyRegion.bounds(), &vaddr, fenceFd);if (res != 0) {err = INVALID_OPERATION;} else {// 3. 锁定成功,更新mLockedBuffer变量,并将锁定的Buffer的信息拷贝回outBuffer并返回给上层mLockedBuffer = backBuffer;outBuffer->width  = backBuffer->width;outBuffer->height = backBuffer->height;outBuffer->stride = backBuffer->stride;outBuffer->format = backBuffer->format;// 4. 将buffer的内存空间地址拷贝到outBuffer中,用于后续的绘制数据填充outBuffer->bits   = vaddr;}}return err;
}// 从BufferQueue中获取一个buffer,并拷贝给入参buffer供上层使用
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {// ...int buf = -1;sp<Fence> fence;nsecs_t startTime = systemTime();FrameEventHistoryDelta frameTimestamps;// 1. 通过mGraphicBufferProducer调用dequeueBuffer方法申请一个buffer,将buffer的槽位赋值给buf变量,将和buffer关联的fence赋值给fence变量(直到fence信号到达之后才能重写buffer的内容)status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, dqInput.width, dqInput.height, dqInput.format, dqInput.usage, &mBufferAge, dqInput.getTimestamps ? &frameTimestamps : nullptr);// ...// 2. 根据槽位buf获取对应的GraphicBuffersp<GraphicBuffer>& gbuf(mSlots[buf].buffer);// ...// 3. 如果fence是有效的,那么将其赋值给入参fenceFd,交由上层使用if (fence->isValid()) {*fenceFd = fence->dup();if (*fenceFd == -1) {ALOGE("dequeueBuffer: error duping fence: %d", errno);}} else {*fenceFd = -1;}// 4. 将获取到的GraphicBuffer赋值给入参buffer,返回给上层使用*buffer = gbuf.get();// ...// 将dequeue的slot记录下来mDequeuedSlots.insert(buf);return OK;
}

Surface::lock方法内部调用了Surface::dequeueBuffer,首先通过mGraphicBufferProducer->dequeueBuffer获取一个GraphicBuffer,然后将获取到的fence以及buffer赋值给入参,交由上层使用。这里的mGraphicBufferProducer是获取GraphicBuffer的关键。在《浅析Android View绘制过程中的Surface》一文中分析了mGraphicBufferProducer是请求SystemServer进程的WindowManagerService更新窗口之后,在App进程创建BLASTBufferQueue对象时创建的,mGraphicBufferProducer持有了BLASTBufferQueue

下面看下mGraphicBufferProducer->dequeueBuffer内部的实现,

// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence, uint32_t width, uint32_t height, PixelFormat format, uint64_t usage, uint64_t* outBufferAge, FrameEventHistoryDelta* outTimestamps) {// ...status_t returnFlags = NO_ERROR;// ...sp<IConsumerListener> listener;bool callOnFrameDequeued = false;uint64_t bufferId = 0; // Only used if callOnFrameDequeued == true// ...{ // Autolock scopestd::unique_lock<std::mutex> lock(mCore->mMutex);// 如果当前没有空闲buffer并且正在分配,则通过锁来等待分配结束。// mFreeBuffers初始化的值是空的集合,mIsAllocating初始化的值为falseif (mCore->mFreeBuffers.empty() && mCore->mIsAllocating) {mDequeueWaitingForAllocation = true;mCore->waitWhileAllocatingLocked(lock);mDequeueWaitingForAllocation = false;mDequeueWaitingForAllocationCondition.notify_all();}// ...int found = BufferItem::INVALID_BUFFER_SLOT;// 循环尝试获取空闲的bufferwhile (found == BufferItem::INVALID_BUFFER_SLOT) {// 1. 阻塞等待有空闲的buffer status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);if (status != NO_ERROR) {return status;}// ...// 第一次返回的found为0const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);// 如果不允许分配新的buffer,那么waitForFreeSlotThenRelock必须返回包含buffer的slot。// 如果这个buffer要求重新分配,那么释放它并尝试获取其他的buffer。// mAllowAllocation初始化的值为trueif (!mCore->mAllowAllocation) {// ...}}// 2. 根据获取到的slot获取对应的GraphicBuffer,由于第一次获取的BufferSlot对象中mGraphicBuffer是默认值nullptrconst sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);bool needsReallocation = buffer == nullptr || buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage);// ...// 即将返回给上层使用,将其状态更新为Activeif (mCore->mSharedBufferSlot != found) {mCore->mActiveBuffers.insert(found);}// 通过outSlot将获取到的slot通过入参返回给上层*outSlot = found;attachedByConsumer = mSlots[found].mNeedsReallocation;mSlots[found].mNeedsReallocation = false;// 更新对应的状态mSlots[found].mBufferState.dequeue();// 3. 需要分配GraphicBuffer,将BufferSlot的成员变量重置,同时设置returnFlags为BUFFER_NEEDS_REALLOCATIONif (needsReallocation) {mSlots[found].mAcquireCalled = false;mSlots[found].mGraphicBuffer = nullptr;mSlots[found].mRequestBufferCalled = false;mSlots[found].mEglDisplay = EGL_NO_DISPLAY;mSlots[found].mEglFence = EGL_NO_SYNC_KHR;mSlots[found].mFence = Fence::NO_FENCE;mCore->mBufferAge = 0;mCore->mIsAllocating = true;returnFlags |= BUFFER_NEEDS_REALLOCATION;} else {// We add 1 because that will be the frame number when this buffer// is queuedmCore->mBufferAge = mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;}eglDisplay = mSlots[found].mEglDisplay;eglFence = mSlots[found].mEglFence;// Don't return a fence in shared buffer mode, except for the first frame.*outFence = (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == found) ? Fence::NO_FENCE : mSlots[found].mFence;mSlots[found].mEglFence = EGL_NO_SYNC_KHR;mSlots[found].mFence = Fence::NO_FENCE;// ...} // Autolock scopeif (returnFlags & BUFFER_NEEDS_REALLOCATION) {// ...// 4. 第3步已经标记了BUFFER_NEEDS_REALLOCATION,所以直接进入if语句块status_t error = graphicBuffer->initCheck();// ...}if (listener != nullptr && callOnFrameDequeued) {listener->onFrameDequeued(bufferId);}// ...if (outBufferAge) {*outBufferAge = mCore->mBufferAge;}addAndGetFrameTimestamps(nullptr, outTimestamps);return returnFlags;
}BufferSlot(): mGraphicBuffer(nullptr),mEglDisplay(EGL_NO_DISPLAY),mBufferState(),mRequestBufferCalled(false),mFrameNumber(0),mEglFence(EGL_NO_SYNC_KHR),mFence(Fence::NO_FENCE),mAcquireCalled(false),mNeedsReallocation(false) {}

dequeueBuffer方法中循环调用了waitForFreeSlotThenRelock方法来获取空闲slotwaitForFreeSlotThenRelock方法根据
BufferQueueCore的成员变量依次从mFreeBuffers以及mFreeSlots中获取可用的slot,第一次调用waitForFreeSlotThenRelock方法获取到的slot为0。之后将会从mSlots中取出slot对应的GraphicBuffer

status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller, std::unique_lock<std::mutex>& lock, int* found) const {auto callerString = (caller == FreeSlotCaller::Dequeue) ? "dequeueBuffer" : "attachBuffer";bool tryAgain = true;while (tryAgain) {// ...int dequeuedCount = 0;int acquiredCount = 0;// 第一次dequeueBuffer时,mActiveBuffers的初始值为空的setfor (int s : mCore->mActiveBuffers) {// }// 不允许dequeue超过mMaxDequeuedBufferCount个buffer,只有queue过buffer才会检查。// mBufferHasBeenQueued初始化的值为falseif (mCore->mBufferHasBeenQueued && dequeuedCount >= mCore->mMaxDequeuedBufferCount) {       return INVALID_OPERATION;}*found = BufferQueueCore::INVALID_BUFFER_SLOT;// If we disconnect and reconnect quickly, we can be in a state where// our slots are empty but we have many buffers in the queue. This can// cause us to run out of memory if we outrun the consumer. Wait here if// it looks like we have too many buffers queued up.const int maxBufferCount = mCore->getMaxBufferCountLocked();bool tooManyBuffers = mCore->mQueue.size() > static_cast<size_t>(maxBufferCount);if (tooManyBuffers) {BQ_LOGV("%s: queue size is %zu, waiting", callerString, mCore->mQueue.size());} else {// mSharedBufferMode为falseif (mCore->mSharedBufferMode && mCore->mSharedBufferSlot !=  BufferQueueCore::INVALID_BUFFER_SLOT) {*found = mCore->mSharedBufferSlot;} else {if (caller == FreeSlotCaller::Dequeue) {// 1. 获取空闲的bufferint slot = getFreeBufferLocked();// 第一次获取由于mFreeBuffers是空的,所以返回了BufferQueueCore::INVALID_BUFFER_SLOTif (slot != BufferQueueCore::INVALID_BUFFER_SLOT) { // 获取到了空间的buffer*found = slot;} else if (mCore->mAllowAllocation) { // 允许为slot分配buffer的情况// 2. 获取空闲的slot// BufferQueueCore实例化的时候mAllowAllocation赋值为true*found = getFreeSlotLocked();}} else {// If we're calling this from attach, prefer free slotsint slot = getFreeSlotLocked();if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {*found = slot;} else {*found = getFreeBufferLocked();}}}}// 如果没有找到buffer,或者queue里有太多的buffer,那么等待一个buffer被acquire或者release,或者最大的buffer数量发生变化。tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || tooManyBuffers;// ...} // while (tryAgain)return NO_ERROR;
}// 获取空闲的buffer
int BufferQueueProducer::getFreeBufferLocked() const {if (mCore->mFreeBuffers.empty()) {return BufferQueueCore::INVALID_BUFFER_SLOT;}// 从mFreeBuffers这个list中获取第一个元素int slot = mCore->mFreeBuffers.front();mCore->mFreeBuffers.pop_front();return slot;
}// 获取空闲的slot,对应的slot还没有分配buffer
int BufferQueueProducer::getFreeSlotLocked() const {// mFreeSlots的初始长度为2if (mCore->mFreeSlots.empty()) {return BufferQueueCore::INVALID_BUFFER_SLOT;}// 第一次取出的slot值为0int slot = *(mCore->mFreeSlots.begin());// 移除0mCore->mFreeSlots.erase(slot);return slot;
}BufferQueueCore::BufferQueueCore(): mMutex(),mIsAbandoned(false),mConsumerControlledByApp(false),mConsumerName(getUniqueName()),mConsumerListener(),mConsumerUsageBits(0),mConsumerIsProtected(false),mConnectedApi(NO_CONNECTED_API),mLinkedToDeath(),mConnectedProducerListener(),mBufferReleasedCbEnabled(false),mBufferAttachedCbEnabled(false),mSlots(),mQueue(),mFreeSlots(),mFreeBuffers(), // 初始化时为空listmUnusedSlots(),mActiveBuffers(),mDequeueCondition(),mDequeueBufferCannotBlock(false),mQueueBufferCanDrop(false),mLegacyBufferDrop(true),mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),mDefaultWidth(1),mDefaultHeight(1),mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),mMaxAcquiredBufferCount(1),mMaxDequeuedBufferCount(1),mBufferHasBeenQueued(false),mFrameCounter(0),mTransformHint(0),mIsAllocating(false),mIsAllocatingCondition(),mAllowAllocation(true),mBufferAge(0),mGenerationNumber(0),mAsyncMode(false),mSharedBufferMode(false),mAutoRefresh(false),mSharedBufferSlot(INVALID_BUFFER_SLOT),mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE, HAL_DATASPACE_UNKNOWN),mLastQueuedSlot(INVALID_BUFFER_SLOT),mUniqueId(getUniqueId()),mAutoPrerotation(false),mTransformHintInUse(0) {// numStartingBuffers为2int numStartingBuffers = getMaxBufferCountLocked();for (int s = 0; s < numStartingBuffers; s++) {mFreeSlots.insert(s);}// mFreeSlots的元素个数为2,取值分别为0、1// BufferQueueDefs::NUM_BUFFER_SLOTS为64for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS; s++) {mUnusedSlots.push_front(s);}// mUnusedSlots的元素个数为62,取值分别为2、3、。。。63
}int BufferQueueCore::getMaxBufferCountLocked() const {// mMaxAcquiredBufferCount为1// mMaxDequeuedBufferCount为1 // mAsyncMode为false// mDequeueBufferCannotBlock为false// maxBufferCount的值为2int maxBufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount + ((mAsyncMode || mDequeueBufferCannotBlock) ? 1 : 0);// mMaxBufferCount为64// maxBufferCount最终为2maxBufferCount = std::min(mMaxBufferCount, maxBufferCount);return maxBufferCount;
}

从上面的代码可以看出,mSlots是元素类型为BufferSlot的数组,长度为64。而BufferSlot实例化的时候默认mGraphicBuffer为空指针,接着就会创建GraphicBuffer对象,并更新到BufferSlot对象中。下面看下GraphicBuffer对象的创建过程,毕竟GraphicBuffer是用于传输图形数据的。

// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence, uint32_t width, uint32_t height, PixelFormat format, uint64_t usage, uint64_t* outBufferAge, FrameEventHistoryDelta* outTimestamps) {// ...uint64_t bufferId = 0; // Only used if callOnFrameDequeued == true// ...{ // Autolock scope// ...int found = BufferItem::INVALID_BUFFER_SLOT;// 循环尝试获取空闲的bufferwhile (found == BufferItem::INVALID_BUFFER_SLOT) {// 1. 阻塞等待可用的空闲buffer status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);if (status != NO_ERROR) {return status;}// ...const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);// ...}// 2. 根据获取到的slot获取对应的GraphicBuffer,第一次获取到的mGraphicBuffer为空指针const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);// needsReallocation为truebool needsReallocation = buffer == nullptr || buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage);// ...// 即将返回给上层使用,将其状态更新为Activeif (mCore->mSharedBufferSlot != found) {mCore->mActiveBuffers.insert(found);}// 3. 通过outSlot将空闲buffer对应的slot返回*outSlot = found;// mNeedsReallocation为falseattachedByConsumer = mSlots[found].mNeedsReallocation;mSlots[found].mNeedsReallocation = false;// 跟新对应的状态mSlots[found].mBufferState.dequeue();// needsReallocation为trueif (needsReallocation) {mSlots[found].mAcquireCalled = false;mSlots[found].mGraphicBuffer = nullptr;mSlots[found].mRequestBufferCalled = false;mSlots[found].mEglDisplay = EGL_NO_DISPLAY;mSlots[found].mEglFence = EGL_NO_SYNC_KHR;mSlots[found].mFence = Fence::NO_FENCE;mCore->mBufferAge = 0;mCore->mIsAllocating = true;returnFlags |= BUFFER_NEEDS_REALLOCATION;} else {// We add 1 because that will be the frame number when this buffer// is queuedmCore->mBufferAge = mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;}eglDisplay = mSlots[found].mEglDisplay;eglFence = mSlots[found].mEglFence;// Don't return a fence in shared buffer mode, except for the first frame.*outFence = (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == found) ? Fence::NO_FENCE : mSlots[found].mFence;mSlots[found].mEglFence = EGL_NO_SYNC_KHR;mSlots[found].mFence = Fence::NO_FENCE;// ...} // Autolock scope// returnFlags & BUFFER_NEEDS_REALLOCATION的结果为trueif (returnFlags & BUFFER_NEEDS_REALLOCATION) {// ...
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)std::vector<GraphicBufferAllocator::AdditionalOptions> tempOptions;tempOptions.reserve(allocOptions.size());for (const auto& it : allocOptions) {tempOptions.emplace_back(it.name.c_str(), it.value);}const GraphicBufferAllocator::AllocationRequest allocRequest = {.importBuffer = true,.width = width,.height = height,.format = format,.layerCount = BQ_LAYER_COUNT,.usage = usage,.requestorName = {mConsumerName.c_str(), mConsumerName.size()},.extras = std::move(tempOptions),};sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(allocRequest);
#elsesp<GraphicBuffer> graphicBuffer = new GraphicBuffer(width, height, format, BQ_LAYER_COUNT, usage, {mConsumerName.c_str(), mConsumerName.size()});
#endifstatus_t error = graphicBuffer->initCheck();{ // Autolock scopestd::lock_guard<std::mutex> lock(mCore->mMutex);// 4. 根据创建的GraphicBuffer更新BufferSlot的mGraphicBufferif (error == NO_ERROR && !mCore->mIsAbandoned) {graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)mSlots[*outSlot].mAdditionalOptionsGenerationId = allocOptionsGenId;
#endifcallOnFrameDequeued = true;bufferId = mSlots[*outSlot].mGraphicBuffer->getId();}mCore->mIsAllocating = false;mCore->mIsAllocatingCondition.notify_all();// ...VALIDATE_CONSISTENCY();} // Autolock scope}if (listener != nullptr && callOnFrameDequeued) {listener->onFrameDequeued(bufferId);}// ...if (outBufferAge) {*outBufferAge = mCore->mBufferAge;}addAndGetFrameTimestamps(nullptr, outTimestamps);return returnFlags;
}

下面看下GraphicBuffer的创建过程,主要实现逻辑在initWithSize方法中,最终通过GraphicBufferAllocator分配器完成内存空间的分配,并将其记录下来。

// frameworks/native/libs/ui/GraphicBuffer.cpp
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage, std::string requestorName) : GraphicBuffer() {mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, std::move(requestorName));
}status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage, std::string requestorName)
{GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();uint32_t outStride = 0;// 分配内存空间status_t err = allocator.allocate(inWidth, inHeight, inFormat, inLayerCount, inUsage, &handle, &outStride, mId, std::move(requestorName));if (err == NO_ERROR) {mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);width = static_cast<int>(inWidth);height = static_cast<int>(inHeight);format = inFormat;layerCount = inLayerCount;usage = inUsage;usage_deprecated = int(usage);stride = static_cast<int>(outStride);}return err;
}// frameworks/native/libs/ui/GraphicBufferAllocator.cpp
status_t GraphicBufferAllocator::allocateHelper(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, buffer_handle_t* handle, uint32_t* stride, std::string requestorName, bool importBuffer) {// ...const uint32_t bpp = bytesPerPixel(format);// ...// Ensure that layerCount is valid.if (layerCount < 1) {layerCount = 1;}// TODO(b/72323293, b/72703005): Remove these invalid bits from callersusage &= ~static_cast<uint64_t>((1 << 10) | (1 << 13));// 1. 分配内存空间的关键实现status_t error = mAllocator->allocate(requestorName, width, height, format, layerCount, usage, stride, handle, importBuffer);if (error != NO_ERROR) {return error;}if (!importBuffer) {return NO_ERROR;}size_t bufSize;// if stride has no meaning or is too large,// approximate size with the input width insteadif ((*stride) != 0 && std::numeric_limits<size_t>::max() / height / (*stride) < static_cast<size_t>(bpp)) {bufSize = static_cast<size_t>(width) * height * bpp;} else {bufSize = static_cast<size_t>((*stride)) * height * bpp;}Mutex::Autolock _l(sLock);KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);alloc_rec_t rec;rec.width = width;rec.height = height;rec.stride = *stride;rec.format = format;rec.layerCount = layerCount;rec.usage = usage;rec.size = bufSize;rec.requestorName = std::move(requestorName);// 2. 记录分配的内存空间以及rec信息list.add(*handle, rec);return NO_ERROR;
}// frameworks/native/libs/ui/include/ui/Gralloc.h
// A wrapper to IAllocator
class GrallocAllocator {
public:/** The returned buffers are already imported and must not be imported* again.  outBufferHandles must point to a space that can contain at* least "bufferCount" buffer_handle_t.* outBufferHandles指向一个内存空间*/virtual status_t allocate(std::string requestorName, uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, uint32_t* outStride, buffer_handle_t* outBufferHandles, bool importBuffers = true) const = 0;
}

从上面可以看到,最终分配的内存空间存储到了GraphicBufferhandle变量里,用于后续的数据写入。至此,整个GraphicBuffer就已经完成创建并attach到了slot中,后续的canvas就可以使用GraphicBuffer进行数据填充了。

使用Canvas对象进行绘制

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks, AttachedSurfaceControl {// ...private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets) {// Draw with software renderer.final Canvas canvas;// ...try {// ...// 1. 根据dirty从Surface对象中锁定一个canvas对象canvas = mSurface.lockCanvas(dirty);// ...} catch (Surface.OutOfResourcesException e) {handleOutOfResourcesException(e);return false;} catch (IllegalArgumentException e) {mLayoutRequested = true;    // ask wm for a new surface next time.return false;} finally {// ...}try {// ...// 2. 遍历绘制子ViewmView.draw(canvas);// ...} finally {try {// 3. 解锁canvas并将数据提交给SurfaceFlinger进程进行合成上屏surface.unlockCanvasAndPost(canvas);} catch (IllegalArgumentException e) {mLayoutRequested = true;    // ask wm for a new surface next time.return false;}}return true;}// ...
}

锁定canvas之后直接将canvas传给了View#draw方法,源码里的注释已经说明了绘制需要做的事情,一般我们关注onDrawdispatchDraw这两个方法,一个适用于绘制自身的内容,一个是用于分发绘制流程到子View

    /*** Manually render this view (and all of its children) to the given Canvas.* The view must have already done a full layout before this function is* called.  When implementing a view, implement* {@link #onDraw(android.graphics.Canvas)} instead of overriding this method.* If you do need to override this method, call the superclass version.** @param canvas The Canvas to which the View is rendered.*/@CallSuperpublic void draw(Canvas canvas) {final int privateFlags = mPrivateFlags;mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;/** Draw traversal performs several drawing steps which must be executed* in the appropriate order:**      1. Draw the background*      2. If necessary, save the canvas' layers to prepare for fading*      3. Draw view's content*      4. Draw children*      5. If necessary, draw the fading edges and restore layers*      6. Draw decorations (scrollbars for instance)*      7. If necessary, draw the default focus highlight*/// 1. 绘制背景int saveCount;drawBackground(canvas);// skip step 2 & 5 if possible (common case)final int viewFlags = mViewFlags;boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;if (!verticalEdges && !horizontalEdges) {// 3. 绘制自身的内容onDraw(canvas);// 4. 绘制子ViewdispatchDraw(canvas);drawAutofilledHighlight(canvas);// Overlay is part of the content and draws beneath Foregroundif (mOverlay != null && !mOverlay.isEmpty()) {mOverlay.getOverlayView().dispatchDraw(canvas);}// 6. 绘制前景onDrawForeground(canvas);// 7. 绘制默认的highlightdrawDefaultFocusHighlight(canvas);if (isShowingLayoutBounds()) {debugDrawFocus(canvas);}// we're done...return;}// ...}

绘制自身的onDraw方法

自定义View的时候需要结合实际需要对onDraw方法进行重写,对于布局类的View则一般不需要重写。下面从TextView#onDraw方法看下一般需要怎么实现。

public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {// .../*** Implement this to do your drawing.** @param canvas the canvas on which the background will be drawn*/protected void onDraw(Canvas canvas) {}// ...
}
public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {// ...@Overrideprotected void onDraw(Canvas canvas) {restartMarqueeIfNeeded();// Draw the background for this viewsuper.onDraw(canvas);// ...canvas.save();int extendedPaddingTop = getExtendedPaddingTop();int extendedPaddingBottom = getExtendedPaddingBottom();final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop;final int maxScrollY = mLayout.getHeight() - vspace;float clipLeft = compoundPaddingLeft + scrollX;float clipTop = (scrollY == 0) ? 0 : extendedPaddingTop + scrollY;float clipRight = right - left - getCompoundPaddingRight() + scrollX;float clipBottom = bottom - top + scrollY - ((scrollY == maxScrollY) ? 0 : extendedPaddingBottom);// ...canvas.clipRect(clipLeft, clipTop, clipRight, clipBottom);int voffsetText = 0;int voffsetCursor = 0;// ...if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) {voffsetText = getVerticalOffset(false);voffsetCursor = getVerticalOffset(true);}canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText);final int layoutDirection = getLayoutDirection();final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);if (isMarqueeFadeEnabled()) {if (!mSingleLine && getLineCount() == 1 && canMarquee() && (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) {final int width = mRight - mLeft;final int padding = getCompoundPaddingLeft() + getCompoundPaddingRight();final float dx = mLayout.getLineRight(0) - (width - padding);canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);}if (mMarquee != null && mMarquee.isRunning()) {final float dx = -mMarquee.getScroll();canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);}}final int cursorOffsetVertical = voffsetCursor - voffsetText;Path highlight = getUpdatedHighlightPath();if (mEditor != null) {mEditor.onDraw(canvas, layout, highlight, mHighlightPaint, cursorOffsetVertical);} else {layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);}if (mMarquee != null && mMarquee.shouldDrawGhost()) {final float dx = mMarquee.getGhostOffset();canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);}canvas.restore();}}

可以看到,TextView#onDraw方法中通过Canvas#save方法以及Canvas#restore对绘制操作进行批量保存,而实际的绘制操作对应的方法包括:Canvas#clipRectCanvas#translate等,跟进去看下方法内部实现会发现,都是通过JNI调用到native层去处理实际逻辑的。

public class Canvas extends BaseCanvas {/*** Saves the current matrix and clip onto a private stack.* <p>* Subsequent calls to translate,scale,rotate,skew,concat or clipRect,* clipPath will all operate as usual, but when the balancing call to* restore() is made, those calls will be forgotten, and the settings that* existed before the save() will be reinstated.** @return The value to pass to restoreToCount() to balance this save()*/public int save() {return nSave(mNativeCanvasWrapper, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);}@CriticalNativeprivate static native int nSave(long canvasHandle, int saveFlags);/*** This call balances a previous call to save(), and is used to remove all* modifications to the matrix/clip state since the last save call. It is* an error to call restore() more times than save() was called.*/public void restore() {if (!nRestore(mNativeCanvasWrapper)&& (!sCompatibilityRestore || !isHardwareAccelerated())) {throw new IllegalStateException("Underflow in restore - more restores than saves");}}@CriticalNativeprivate static native boolean nRestore(long canvasHandle);/*** Intersect the current clip with the specified rectangle, which is* expressed in local coordinates.** @param left   The left side of the rectangle to intersect with the*               current clip* @param top    The top of the rectangle to intersect with the current clip* @param right  The right side of the rectangle to intersect with the*               current clip* @param bottom The bottom of the rectangle to intersect with the current*               clip* @return       true if the resulting clip is non-empty*/public boolean clipRect(float left, float top, float right, float bottom) {return nClipRect(mNativeCanvasWrapper, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);}@CriticalNativeprivate static native boolean nClipRect(long nativeCanvas, float left, float top, float right, float bottom, int regionOp);}

下面跟进去看下内部是如何处理的。
ToDo

分发绘制流程

调用dispatchDraw方法绘制子View,具体实现在ViewGroup类中,如果自定义View继承了ViewGroup则根据实际需要进行重写。dispatchDraw方法内部主要是遍历子View并调用其draw方法来对子View进行绘制。

public abstract class ViewGroup extends View implements ViewParent, ViewManager {// ...@Overrideprotected void dispatchDraw(Canvas canvas) {final int childrenCount = mChildrenCount;final View[] children = mChildren;int flags = mGroupFlags;// ...int clipSaveCount = 0;final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;if (clipToPadding) {clipSaveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop, mScrollX + mRight - mLeft - mPaddingRight, mScrollY + mBottom - mTop - mPaddingBottom);}// ...boolean more = false;final long drawingTime = getDrawingTime();canvas.enableZ();final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();int transientIndex = transientCount != 0 ? 0 : -1;// 硬件加速未开启时preorderedList才不会nullfinal ArrayList<View> preorderedList = drawsWithRenderNode(canvas) ? null : buildOrderedChildList();final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled();for (int i = 0; i < childrenCount; i++) {while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {final View transientChild = mTransientViews.get(transientIndex);if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE || transientChild.getAnimation() != null) {more |= drawChild(canvas, transientChild, drawingTime);}transientIndex++;if (transientIndex >= transientCount) {transientIndex = -1;}}final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {// 调用drawChild绘制子Viewmore |= drawChild(canvas, child, drawingTime);}}while (transientIndex >= 0) {// there may be additional transient views after the normal viewsfinal View transientChild = mTransientViews.get(transientIndex);if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE || transientChild.getAnimation() != null) {more |= drawChild(canvas, transientChild, drawingTime);}transientIndex++;if (transientIndex >= transientCount) {break;}}if (preorderedList != null) preorderedList.clear();// Draw any disappearing views that have animationsif (mDisappearingChildren != null) {final ArrayList<View> disappearingChildren = mDisappearingChildren;final int disappearingCount = disappearingChildren.size() - 1;// Go backwards -- we may delete as animations finishfor (int i = disappearingCount; i >= 0; i--) {final View child = disappearingChildren.get(i);more |= drawChild(canvas, child, drawingTime);}}canvas.disableZ();if (clipToPadding) {canvas.restoreToCount(clipSaveCount);}// mGroupFlags might have been updated by drawChild()flags = mGroupFlags;if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {invalidate(true);}// ...}// .../*** Draw one child of this View Group. This method is responsible for getting* the canvas in the right state. This includes clipping, translating so* that the child's scrolled origin is at 0, 0, and applying any animation* transformations.** @param canvas The canvas on which to draw the child* @param child Who to draw* @param drawingTime The time at which draw is occurring* @return True if an invalidate() was issued*/protected boolean drawChild(Canvas canvas, View child, long drawingTime) {return child.draw(canvas, this, drawingTime);}
}

遍历完整个View树之后,对于所有绘制操作完成了处理,此时就可以将处理之后得到的数据提交,用于后续的合成上屏了。

提交图形数据

提交数据是通过Surface#unlockCanvasAndPost方法完成的,下面跟一下源码看下具体做了什么事情。

public class Surface implements Parcelable {// .../*** Posts the new contents of the {@link Canvas} to the surface and* releases the {@link Canvas}.** @param canvas The canvas previously obtained from {@link #lockCanvas}.*/public void unlockCanvasAndPost(Canvas canvas) {synchronized (mLock) {checkNotReleasedLocked();// 软件绘制(未开启硬件加速)时mHwuiContext为nullif (mHwuiContext != null) {mHwuiContext.unlockAndPost(canvas);} else {unlockSwCanvasAndPost(canvas);}}}private void unlockSwCanvasAndPost(Canvas canvas) {if (canvas != mCanvas) {throw new IllegalArgumentException("canvas object must be the same instance that "+ "was previously returned by lockCanvas");}if (mNativeObject != mLockedObject) {Log.w(TAG, "WARNING: Surface's mNativeObject (0x" + Long.toHexString(mNativeObject) + ") != mLockedObject (0x" + Long.toHexString(mLockedObject) +")");}if (mLockedObject == 0) {throw new IllegalStateException("Surface was not locked");}try {nativeUnlockCanvasAndPost(mLockedObject, canvas);} finally {nativeRelease(mLockedObject);mLockedObject = 0;}}private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas);@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)private static native void nativeRelease(long nativeObject);// ...
}

总结

硬件渲染

为了提升Android系统的渲染能力,从Android 3.0开始支持硬件加速,Android 4.0默认开启硬件加速,Android 4.1引入VSYNC以及Triple Buffers机制,在Android 4.2还引入了过度渲染监控工具。为了进一步提升渲染性能,Android 5.0开始引入RenderNode以及RenderThread分别用于减少重复绘制以及异步处理GL命令,并且在Android 7.0引入Vulkan硬件渲染引擎。

对于硬件渲染机制而言,ThreadedRenderer在硬件绘制流程中起到重要的作用,因此先对ThreadedRenderer的创建进行分析,在《浅析Android中的Choreographer工作原理》中有分析到,在调度VSYNC信号之前会通过ViewRootImpl#setView方法将DecorViewViewRootImpl进行关联,并且会创建ThreadedRenderer实例用于后续的硬件渲染流程。

ThreadedRenderer的创建

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks, AttachedSurfaceControl {public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) {synchronized (this) {if (mView == null) {mView = view;// ...// mSurfaceHolder == nullif (mSurfaceHolder == null) {// While this is supposed to enable only, it can effectively disable// the acceleration too.enableHardwareAcceleration(attrs);final boolean useMTRenderer = MT_RENDERER_AVAILABLE && mAttachInfo.mThreadedRenderer != null;if (mUseMTRenderer != useMTRenderer) {// Shouldn't be resizing, as it's done only in window setup,// but end just in case.endDragResizing();mUseMTRenderer = useMTRenderer;}}// ...		}}}private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {mAttachInfo.mHardwareAccelerated = false;mAttachInfo.mHardwareAccelerationRequested = false;// Don't enable hardware acceleration when the application is in compatibility modeif (mTranslator != null) return;// Try to enable hardware acceleration if requestedfinal boolean hardwareAccelerated = (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;if (hardwareAccelerated) {final boolean forceHwAccelerated = (attrs.privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;// 开启硬件加速的情况if (ThreadedRenderer.sRendererEnabled || forceHwAccelerated) {if (mAttachInfo.mThreadedRenderer != null) {mAttachInfo.mThreadedRenderer.destroy();}final Rect insets = attrs.surfaceInsets;final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0 || insets.top != 0 || insets.bottom != 0;final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;// 1. 创建ThreadedRenderer对象并赋值给mAttachInfo.mThreadedRenderermAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent, attrs.getTitle().toString());updateColorModeIfNeeded(attrs.getColorMode());updateForceDarkMode();if (mAttachInfo.mThreadedRenderer != null) {// 2. 更新硬件加速相关的字段mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested = true;if (mHardwareRendererObserver != null) {mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);}// 3. 将mSurfaceControl以及mBlastBufferQueue设置到mThreadedRenderer中,用于后续的绘制渲染mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl);mAttachInfo.mThreadedRenderer.setBlastBufferQueue(mBlastBufferQueue);}// ...}}}// ...
}

根据源码可以看出,在调度VSYNC信号之前会创建ThreadedRenderer对象并将其保存在mAttachInfo中,同时更新mAttachInfo中硬件加速相关的字段,最后将mSurfaceControl以及mBlastBufferQueue设置到mThreadedRenderer中,用于后续的绘制渲染。

下面看下ThreadedRenderer对象的创建过程都做了哪些事情。

/*** ThreadedRenderer将渲染工作放到了一个render线程中执行,UI线程可以阻塞render线程,但是render线程不能阻塞UI线程。* ThreadedRenderer创建了RenderProxy实例,RenderProxy创建并管理了render线程中的CanvasContext,CanvasContext完全由RenderProxy的生命周期所管理。*/
public final class ThreadedRenderer extends HardwareRenderer {/*** 使用OpenGL创建一个ThreadedRenderer实例.** @param translucent True if the surface is translucent, false otherwise** @return A threaded renderer backed by OpenGL.*/public static ThreadedRenderer create(Context context, boolean translucent, String name) {return new ThreadedRenderer(context, translucent, name);}ThreadedRenderer(Context context, boolean translucent, String name) {// 调用了HardwareRenderer的构造函数super();setName(name);setOpaque(!translucent);final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);float ambientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0);float spotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0);a.recycle();setLightSourceAlpha(ambientShadowAlpha, spotShadowAlpha);}
}

可以看出,ThreadedRenderer对象的创建过程中比较关键的部分是父类HardwareRenderer的构造函数。

/*** 创建一个硬件加速的render实例,用于将RenderNode渲染到Surface上。* 所有的HardwareRenderer实例共享一个render线程。render线程包含用于GPU加速渲染所需的GPU上下文以及资源。* 第一个HardwareRenderer创建的同时还伴随着创建GPU上下文的开销,但是之后的每个HardwareRenderer实例的创建开销小。* 推荐的使用方式是每一个处于使用状态的Surface对象共享同一个HardwareRenderer实例。* 比如,当一个Activity展示一个Dialog时,系统内部会使用两个HardwareRenderer实例,可能两个HardwareRenderer同时都在绘制。 */
public class HardwareRenderer {protected RenderNode mRootNode; // 根节点private final long mNativeProxy; // native层的渲染代理对象public HardwareRenderer() {// 初始化ContextProcessInitializer.sInstance.initUsingContext();// 1. 在native层创建RenderNode对象,根据返回的句柄值创建Java层的RenderNode对象(根节点)mRootNode = RenderNode.adopt(nCreateRootRenderNode());mRootNode.setClipToBounds(false);// 2. 调用nCreateProxy在native层创建一个渲染代理对象,返回句柄值mNativeProxy = nCreateProxy(!mOpaque, mRootNode.mNativeRenderNode);if (mNativeProxy == 0) {throw new OutOfMemoryError("Unable to create hardware renderer");}Cleaner.create(this, new DestroyContextRunnable(mNativeProxy));// 3. 根据native层的渲染代理对象对ProcessInitializer.sInstance.init(mNativeProxy);}private static native long nCreateRootRenderNode();public static RenderNode adopt(long nativePtr) {return new RenderNode(nativePtr);}private static native long nCreateProxy(boolean translucent, long rootRenderNode);private static class ProcessInitializer {synchronized void init(long renderProxy) {if (mInitialized) return;mInitialized = true;// 初始化render线程信息initSched(renderProxy);// 请求buffer并将对应的fd传设置到native层initGraphicsStats();}}
}

分析源码可知,ThreadedRenderer对象的创建主要包含:

  • 创建根渲染节点
  • 创建渲染代理对象

native层的根渲染节点的创建

public class HardwareRenderer {protected RenderNode mRootNode; // 根节点// ...public HardwareRenderer() {// 初始化ContextProcessInitializer.sInstance.initUsingContext();// 1. 在native层创建RenderNode对象,根据返回的句柄值创建Java层的RenderNode对象(根节点)mRootNode = RenderNode.adopt(nCreateRootRenderNode());mRootNode.setClipToBounds(false);// 2. 调用nCreateProxy在native层创建一个渲染代理对象,返回句柄值// ...// 3. 根据native层的渲染代理对象对// ...}private static native long nCreateRootRenderNode();
}public final class RenderNode {// native层的RenderNode的句柄值public final long mNativeRenderNode;private RenderNode(long nativePtr) {mNativeRenderNode = nativePtr;NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode);mAnimationHost = null;}// ...
}

可以看到Java层的RenderNode其实是一个壳,其内部实现还是在native层,即通过nCreateRootRenderNode方法调用到native层进行RenderNode的创建。

在这里插入代码片

渲染代理对象的创建

public class HardwareRenderer {protected RenderNode mRootNode; // 根节点private final long mNativeProxy; // native层的渲染代理对象public HardwareRenderer() {// 初始化ContextProcessInitializer.sInstance.initUsingContext();// 1. 在native层创建RenderNode对象,根据返回的句柄值创建Java层的RenderNode对象(根节点)// ...// 2. 调用nCreateProxy在native层创建一个渲染代理对象,返回句柄值mNativeProxy = nCreateProxy(!mOpaque, mRootNode.mNativeRenderNode);// ...// 3. 根据native层的渲染代理对象对ProcessInitializer.sInstance.init(mNativeProxy);}private static native long nCreateProxy(boolean translucent, long rootRenderNode);

可以看到渲染代理对象是在native层创建的,并且在创建渲染代理对象时用到了native层的RenderNode

在这里插入代码片

绑定Surface

View的绘制分发

开启硬件加速之后,View的绘制是通过ThreadedRenderer#draw方法来实现的,下面跟一下源码看下,ThreadedRenderer#draw方法内部具体做了哪些事情。

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks, AttachedSurfaceControl {// ...private boolean performDraw() {final boolean fullRedrawNeeded = mFullRedrawNeeded || mSyncBufferCallback != null;// ...// 软件绘制时,usingAsyncReport为falseboolean usingAsyncReport = isHardwareEnabled() && mSyncBufferCallback != null;// ...try {boolean canUseAsync = draw(fullRedrawNeeded, usingAsyncReport && mSyncBuffer);// ...} finally {// ...}// ...}private boolean draw(boolean fullRedrawNeeded, boolean forceDraw) {Surface surface = mSurface;// surface不可用时直接return,而surface在经过relayoutWindow之后已经被更新并处于可用状态if (!surface.isValid()) {return false;}// ...final Rect dirty = mDirty;if (fullRedrawNeeded) {dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));}// ...if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {if (isHardwareEnabled()) {// ...// 开启硬件绘制时,使用ThreadedRenderer进行绘制mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);} else {// 未开启硬件绘制时,使用软件绘制,surface就是成员变量mSurface// ...}}// 如果当前正在动画,调度下一次VSYNC信号来执行布局流程if (animating) {mFullRedrawNeeded = true;scheduleTraversals();}return useAsyncReport;}
}

从源码可以看出,ThreadedRenderer#draw方法主要做了两件事情:

  • 更新根节点的DisplayList
  • 将RenderNode树同步到渲染线程并请求绘制下一帧
public final class ThreadedRenderer extends HardwareRenderer {// ...void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {attachInfo.mViewRootImpl.mViewFrameInfo.markDrawStart();// 1. 更新根节点的DisplayListupdateRootDisplayList(view, callbacks);// 注册在创建ThreadedRenderer之前就启动的动画的渲染节点,这些动画通常在第一次draw之前就开始了。if (attachInfo.mPendingAnimatingRenderNodes != null) {final int count = attachInfo.mPendingAnimatingRenderNodes.size();for (int i = 0; i < count; i++) {registerAnimatingRenderNode(attachInfo.mPendingAnimatingRenderNodes.get(i));}attachInfo.mPendingAnimatingRenderNodes.clear();attachInfo.mPendingAnimatingRenderNodes = null;}final FrameInfo frameInfo = attachInfo.mViewRootImpl.getUpdatedFrameInfo();// 2. 将RenderNode树同步到渲染线程并请求绘制下一帧int syncResult = syncAndDrawFrame(frameInfo);if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {Log.w("OpenGLRenderer", "Surface lost, forcing relayout");// 丢失了surface,因此重新发起布局请求,下一次布局时WindowManager会提供新的surface。attachInfo.mViewRootImpl.mForceNextWindowRelayout = true;attachInfo.mViewRootImpl.requestLayout();}if ((syncResult & SYNC_REDRAW_REQUESTED) != 0) {attachInfo.mViewRootImpl.invalidate();}}// 将RenderNode树同步到渲染线程并请求绘制下一帧@SyncAndDrawResultpublic int syncAndDrawFrame(@NonNull FrameInfo frameInfo) {return nSyncAndDrawFrame(mNativeProxy, frameInfo.frameInfo, frameInfo.frameInfo.length);}
}

更新根节点的DisplayList

从源码可以看出,ThreadedRenderer#updateRootDisplayList方法并不是只会更新根ViewDisplayList,而是会先遍历View树进行DisplayList的更新,然后再更新根ViewDisplayList

public final class ThreadedRenderer extends HardwareRenderer {// ...private void updateRootDisplayList(View view, DrawCallbacks callbacks) {Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()");// 1. 从根View开始遍历更新View树上的DisplayListupdateViewTreeDisplayList(view);// Consume and set the frame callback after we dispatch draw to the view above, but before// onPostDraw below which may reset the callback for the next frame.  This ensures that// updates to the frame callback during scroll handling will also apply in this frame.if (mNextRtFrameCallbacks != null) {final ArrayList<FrameDrawingCallback> frameCallbacks = mNextRtFrameCallbacks;mNextRtFrameCallbacks = null;setFrameCallback(new FrameDrawingCallback() {@Overridepublic void onFrameDraw(long frame) {}@Overridepublic FrameCommitCallback onFrameDraw(int syncResult, long frame) {ArrayList<FrameCommitCallback> frameCommitCallbacks = new ArrayList<>();for (int i = 0; i < frameCallbacks.size(); ++i) {FrameCommitCallback frameCommitCallback = frameCallbacks.get(i).onFrameDraw(syncResult, frame);if (frameCommitCallback != null) {frameCommitCallbacks.add(frameCommitCallback);}}if (frameCommitCallbacks.isEmpty()) {return null;}return didProduceBuffer -> {for (int i = 0; i < frameCommitCallbacks.size(); ++i) {frameCommitCallbacks.get(i).onFrameCommit(didProduceBuffer);}};}});}// 2. 如果根渲染节点需要更新或者根渲染节点没有DisplayList,则对根渲染节点进行处理if (mRootNodeNeedsUpdate || !mRootNode.hasDisplayList()) {RecordingCanvas canvas = mRootNode.beginRecording(mSurfaceWidth, mSurfaceHeight);try {final int saveCount = canvas.save();canvas.translate(mInsetLeft, mInsetTop);callbacks.onPreDraw(canvas);canvas.enableZ();// 将根View的DisplayList填充到canvascanvas.drawRenderNode(view.updateDisplayListIfDirty());canvas.disableZ();callbacks.onPostDraw(canvas);canvas.restoreToCount(saveCount);mRootNodeNeedsUpdate = false;} finally {mRootNode.endRecording();}}Trace.traceEnd(Trace.TRACE_TAG_VIEW);}private void updateViewTreeDisplayList(View view) {view.mPrivateFlags |= View.PFLAG_DRAWN;// 更新mRecreateDisplayList,如果view调用过invalidate方法则标记其需要重新创建DisplayListview.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) == View.PFLAG_INVALIDATED;view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;// 调用View#updateDisplayListIfDirty,方法内部会分发更新的动作view.updateDisplayListIfDirty();view.mRecreateDisplayList = false;}// ...
}

每个View实例在创建的时候都会创建自身的RenderNode,在调用了根ViewupdateDisplayListIfDirty方法之后,首先会判断是否需要重新创建自身的DisplayList,如果不需要则直接调用dispatchGetDisplayList方法将更新操作分发给所有的子View,否则对根View进行必要的绘制,并将绘制操作分发给所有的子View

public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {// 获取这个view的RenderNode实例并根据需要对其DisplayList进行更新@NonNull@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)public RenderNode updateDisplayListIfDirty() {final RenderNode renderNode = mRenderNode;// 只有view已经被attach过并且开启硬件加速才会有DisplayListif (!canHaveDisplayList()) {return renderNode;}// 如果绘制缓存无效或者没有DisplayList或者mRecreateDisplayList被设置为true,则需要进一步处理if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || !renderNode.hasDisplayList() || (mRecreateDisplayList)) {// 不需要重新创建当前View的DisplayList,只需要通知子View恢复或重建他们的DisplayList。// 这种情况对应的是(mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0,但是硬件加速开启的情况下,主要根据hasDisplayList以及mRecreateDisplayList来判断是否需要重建DisplayListif (renderNode.hasDisplayList() && !mRecreateDisplayList) {mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;mPrivateFlags &= ~PFLAG_DIRTY_MASK;// 通知子View恢复或重建他们的DisplayListdispatchGetDisplayList();return renderNode; // no work needed}// 需要重新创建当前View的DisplayList,将mRecreateDisplayList置为true来保证当调用drawChild方法时可以将子View的DisplayList拷贝到当前View的DisplayList里。mRecreateDisplayList = true;int width = mRight - mLeft;int height = mBottom - mTop;int layerType = getLayerType();renderNode.clearStretch();// 开始记录当前View的绘制命令final RecordingCanvas canvas = renderNode.beginRecording(width, height);try {if (layerType == LAYER_TYPE_SOFTWARE) { // 软件绘制时 // ...} else { // 硬件绘制时// ...// 如果当前View是布局类型的并且没有背景,此时直接跳过自身的绘制。if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {// 分发给子View进行绘制dispatchDraw(canvas);// ...} else {// 绘制自身到canvasdraw(canvas);}}} finally {// 结束记录当前View的绘制命令renderNode.endRecording();setDisplayListProperties(renderNode);}} else {mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;mPrivateFlags &= ~PFLAG_DIRTY_MASK;}return renderNode;}/*** View类没有实现此方法,因为只有继承自ViewGroup的View才需要分发给子View。* ViewGroup类中遍历所有的子View并调用其updateDisplayListIfDirty方法,由此开启新一轮的分发处理。* It is called by getDisplayList() when the parent ViewGroup does not need* to recreate its own display list, which would happen if it went through the normal* draw/dispatchDraw mechanisms.** @hide*/protected void dispatchGetDisplayList() {}/*** View类没有实现此方法,因为只有继承自ViewGroup的View才需要分发给子View。* ViewGroup类中遍历所有的子View并调用其draw方法,由此开启新一轮的分发处理。*/protected void dispatchDraw(Canvas canvas) {}// ...
}

可见updateDisplayListIfDirty方法主要完成了绘制任务的分发以及根View自身的绘制。View自身的绘制是通过draw方法实现的,而软件绘制其实也是通过这个draw方法实现的自身绘制,因此这块就不重复分析了。

public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {/*** Manually render this view (and all of its children) to the given Canvas.* The view must have already done a full layout before this function is* called.  When implementing a view, implement* {@link #onDraw(android.graphics.Canvas)} instead of overriding this method.* If you do need to override this method, call the superclass version.** @param canvas The Canvas to which the View is rendered.*/@CallSuperpublic void draw(Canvas canvas) {final int privateFlags = mPrivateFlags;mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;/** Draw traversal performs several drawing steps which must be executed* in the appropriate order:**      1. Draw the background*      2. If necessary, save the canvas' layers to prepare for fading*      3. Draw view's content*      4. Draw children*      5. If necessary, draw the fading edges and restore layers*      6. Draw decorations (scrollbars for instance)*      7. If necessary, draw the default focus highlight*/// Step 1, draw the background, if neededint saveCount;drawBackground(canvas);// skip step 2 & 5 if possible (common case)final int viewFlags = mViewFlags;boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;if (!verticalEdges && !horizontalEdges) {// Step 3, draw the contentonDraw(canvas);// Step 4, draw the childrendispatchDraw(canvas);drawAutofilledHighlight(canvas);// Overlay is part of the content and draws beneath Foregroundif (mOverlay != null && !mOverlay.isEmpty()) {mOverlay.getOverlayView().dispatchDraw(canvas);}// Step 6, draw decorations (foreground, scrollbars)onDrawForeground(canvas);// Step 7, draw the default focus highlightdrawDefaultFocusHighlight(canvas);if (isShowingLayoutBounds()) {debugDrawFocus(canvas);}// we're done...return;}// ...}}

总结下整体的流程如下图所示:

同步数据到渲染线程

public final class ThreadedRenderer extends HardwareRenderer {// ...void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {attachInfo.mViewRootImpl.mViewFrameInfo.markDrawStart();// 1. 更新根节点的DisplayList// ...final FrameInfo frameInfo = attachInfo.mViewRootImpl.getUpdatedFrameInfo();// 2. 将RenderNode树同步到渲染线程并请求绘制下一帧int syncResult = syncAndDrawFrame(frameInfo);if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {Log.w("OpenGLRenderer", "Surface lost, forcing relayout");// 丢失了surface,因此重新发起布局请求,下一次布局时WindowManager会提供新的surface。attachInfo.mViewRootImpl.mForceNextWindowRelayout = true;attachInfo.mViewRootImpl.requestLayout();}if ((syncResult & SYNC_REDRAW_REQUESTED) != 0) {attachInfo.mViewRootImpl.invalidate();}}// 将RenderNode树同步到渲染线程并请求绘制下一帧@SyncAndDrawResultpublic int syncAndDrawFrame(@NonNull FrameInfo frameInfo) {return nSyncAndDrawFrame(mNativeProxy, frameInfo.frameInfo, frameInfo.frameInfo.length);}
}

可以看到完成了绘制命令的收集之后,通过nSyncAndDrawFrame方法调用到了native层,并通过native层的渲染代理进行数据同步。

总结

关键字:建网站要先建什么_网业游戏大全_360搜图片识图_提高搜索引擎检索效果的方法

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: