软硬件绘制的分歧点 绘制过程入口位于ViewRootImpl.performDraw()中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private void performDraw () { ... try { boolean canUseAsync = draw(fullRedrawNeeded); if (usingAsyncReport && !canUseAsync) { mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null ); usingAsyncReport = false ; } } finally { mIsDrawing = false ; Trace.traceEnd(Trace.TRACE_TAG_VIEW); } }
ViewRootImpl.draw()实际执行的绘制工作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 private boolean draw (boolean fullRedrawNeeded) { ... final Rect dirty = mDirty; ... if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) { if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) { ... mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this , callback); } else { ... if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty, surfaceInsets)) { return false ; } } ... } ... }
软件绘制
ViewRootImpl软件绘制相关
未开启硬件加速时,执行到drawSoftware()
1 2 3 4 5 6 7 8 9 10 11 12 private boolean drawSoftware (Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets) { final Canvas canvas; canvas = mSurface.lockCanvas(dirty); ... mView.draw(canvas); ... surface.unlockCanvasAndPost(canvas); }
此处的mView对应的就是DecorView
1 2 3 4 5 6 7 8 9 @Override public void draw (Canvas canvas) { super .draw(canvas); if (mMenuBackground != null ) { mMenuBackground.draw(canvas); } }
执行到super.draw(),DecorView继承自FrameLayout,等价于执行到ViewGroup.draw()。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public void draw (Canvas canvas) { ... if (!dirtyOpaque) { drawBackground(canvas); } if (!dirtyOpaque) onDraw(canvas); dispatchDraw(canvas); onDrawForeground(canvas); ... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 protected void dispatchDraw (Canvas canvas) { ... final ArrayList<View> preorderedList = usingRenderNodeProperties ? 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 ) { more |= drawChild(canvas, child, drawingTime); } } } protected boolean drawChild (Canvas canvas, View child, long drawingTime) { return child.draw(canvas, this , drawingTime); }
DecorView是最顶层的View,自drawSoftware()开始绘制。
View软件绘制相关 上一节后面执行到了child.draw(),child为View
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 boolean draw (Canvas canvas, ViewGroup parent, long drawingTime) { final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); boolean drawingWithRenderNode = mAttachInfo != null && mAttachInfo.mHardwareAccelerated && hardwareAcceleratedCanvas; ... if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { if (layerType != LAYER_TYPE_NONE) { layerType = LAYER_TYPE_SOFTWARE; buildDrawingCache(true ); } cache = getDrawingCache(true ); } final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; ... if (!drawingWithDrawingCache) { if (drawingWithRenderNode) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; ((DisplayListCanvas) canvas).drawRenderNode(renderNode); } else { if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; dispatchDraw(canvas); } else { draw(canvas); } } } ... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 if ((changed & DRAW_MASK) != 0 ) { if ((mViewFlags & WILL_NOT_DRAW) != 0 ) { if (mBackground != null || mDefaultFocusHighlight != null || (mForegroundInfo != null && mForegroundInfo.mDrawable != null )) { mPrivateFlags &= ~PFLAG_SKIP_DRAW; } else { mPrivateFlags |= PFLAG_SKIP_DRAW; } } else { mPrivateFlags &= ~PFLAG_SKIP_DRAW; } requestLayout(); invalidate(true ); }
软件绘制流程
Surface绘制流程
执行到drawSoftware()时,开始在Surface上进行绘制。
申请GraphicBuffer 执行的是mSurface.lockCanvas()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 canvas = mSurface.lockCanvas() public Canvas lockCanvas (Rect inOutDirty) throws Surface.OutOfResourcesException, IllegalArgumentException { synchronized (mLock) { checkNotReleasedLocked(); if (mLockedObject != 0 ) { throw new IllegalArgumentException("Surface was already locked" ); } mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty); return mCanvas; } }
执行到nativeLockCanvas()进入JNI代码层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 static jlong nativeLockCanvas (JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) { sp<Surface> surface (reinterpret_cast <Surface *>(nativeObject)) ; ... ANativeWindow_Buffer outBuffer; status_t err = surface->lock(&outBuffer, dirtyRectPtr); ... SkImageInfo info = SkImageInfo::Make(outBuffer.width , outBuffer.height , convertPixelFormat(outBuffer.format), outBuffer.format == PIXEL_FORMAT_RGBX_8888 ? kOpaque_SkAlphaType : kPremul_SkAlphaType, GraphicsJNI::defaultColorSpace()); 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 { bitmap.setPixels(NULL ); } Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj); nativeCanvas->setBitmap(bitmap); sp<Surface> lockedSurface (surface) ; lockedSurface->incStrong(&sRefBaseOwner); return (jlong) lockedSurface.get (); }
创建完ANativeWindowBuffer之后,需要与surface进行绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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)) ; const Rect bounds (backBuffer->width , backBuffer->height ) ; ... } return err; }
调用到lock()之后,将ANativeWindowBuffer转化为GraphicBuffer。再通过dequeueBuffer分配内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 int Surface::dequeueBuffer (android_native_buffer_t ** buffer , int * fenceFd) { ... FrameEventHistoryDelta frameTimestamps; status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight, reqFormat, reqUsage, &mBufferAge, enableFrameTimestamps ? &frameTimestamps : nullptr ); ... if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr ) { if (mReportRemovedBuffers && (gbuf != nullptr )) { mRemovedBuffers.push_back(gbuf); } result = mGraphicBufferProducer->requestBuffer(buf, &gbuf); if (result != NO_ERROR) { ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d" , result); mGraphicBufferProducer->cancelBuffer(buf, fence); return result; } } *buffer = gbuf.get (); ... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 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) { ... while (found == BufferItem::INVALID_BUFFER_SLOT) { status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, &found); if (status != NO_ERROR) { return status; } ... } *outSlot = found; ATRACE_BUFFER_INDEX(found); attachedByConsumer = mSlots[found].mNeedsReallocation; mSlots[found].mNeedsReallocation = false ; mSlots[found].mBufferState.dequeue(); ... if (returnFlags & BUFFER_NEEDS_REALLOCATION) { BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d" , *outSlot); sp<GraphicBuffer> graphicBuffer = new GraphicBuffer( width , height , format, BQ_LAYER_COUNT, usage, {mConsumerName.string (), mConsumerName.size ()}); status_t error = graphicBuffer->initCheck(); if (error == NO_ERROR && !mCore->mIsAbandoned) { graphicBuffer->setGenerationNumber(mCore->mGenerationNumber); mSlots[*outSlot].mGraphicBuffer = graphicBuffer; } ... } status_t BufferQueueProducer::waitForFreeSlotThenRelock (FreeSlotCaller caller, int * found) const { ... 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 { if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = mCore->mSharedBufferSlot; } else { if (caller == FreeSlotCaller::Dequeue) { int slot = getFreeBufferLocked(); if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = slot; } else if (mCore->mAllowAllocation) { *found = getFreeSlotLocked(); } } else { int slot = getFreeSlotLocked(); if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = slot; } else { *found = getFreeBufferLocked(); } } } } ... tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || tooManyBuffers; if (tryAgain) { } }
BufferSlot:用来存储GraphicBuffer
waitForFreeSlotThenRelock()返回可用的slot分为两种:
getFreeBufferLocked():直接关联了GraphicBuffer,直接可用
getFreeSlotLocked():找到可用的BufferSlot,新建GraphicBuffer后,直接与其关联。
lockCanvas()最终通过BufferQueueProducer.dequeueBuffer()申请用来绘制的GraphicBuffer
尝试找到一个BufferSlot,并完成GraphicBuffer与BufferSlot的关联,途中切换BufferSlot状态FREE->DEQUEUED,最后返回对应的BufferSlot索引。
SurfaceFlinger消费GraphicBuffer当Cavans绘制完毕后,调用surface.unlockAndPostCanvas()发送GraphicBuffer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public void unlockAndPostCanvas (Canvas canvas) { synchronized (mLock) { checkNotReleasedLocked(); if (mHwuiContext != null ) { mHwuiContext.unlockAndPost(canvas); } else { unlockSwCanvasAndPost(canvas); } } } private void unlockSwCanvasAndPost (Canvas canvas) { ... try { nativeUnlockCanvasAndPost(mLockedObject, canvas); } finally { nativeRelease(mLockedObject); mLockedObject = 0 ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 static void nativeUnlockCanvasAndPost (JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj) { ... Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj); nativeCanvas->setBitmap(SkBitmap()); status_t err = surface->unlockAndPost(); if (err < 0 ) { doThrowIAE(env); } }
1 2 3 4 5 6 7 8 9 10 11 12 status_t Surface::unlockAndPost () { ... err = queueBuffer(mLockedBuffer.get (), fd); ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)" , mLockedBuffer->handle, strerror(-err)); mPostedBuffer = mLockedBuffer; mLockedBuffer = 0 ; return err; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 int Surface::queueBuffer (android_native_buffer_t * buffer , int fenceFd) { ... int i = getSlotFromBufferLocked(buffer ); ... status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); ... mQueueBufferCondition.broadcast(); } int Surface::getSlotFromBufferLocked ( android_native_buffer_t * buffer ) const { for (int i = 0 ; i < NUM_BUFFER_SLOTS; i++) { if (mSlots[i].buffer != NULL && mSlots[i].buffer ->handle == buffer ->handle) { return i; } } ALOGE("getSlotFromBufferLocked: unknown buffer: %p" , buffer ->handle); return BAD_VALUE; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 status_t BufferQueueProducer::queueBuffer(int slot, const QueueBufferInput &input, QueueBufferOutput *output) { BufferItem item; ... if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)" , slot, BufferQueueDefs::NUM_BUFFER_SLOTS); return BAD_VALUE; } else if (!mSlots[slot].mBufferState.isDequeued()) { BQ_LOGE("queueBuffer: slot %d is not owned by the producer " "(state = %s)" , slot, mSlots[slot].mBufferState.string()); return BAD_VALUE; } else if (!mSlots[slot].mRequestBufferCalled) { BQ_LOGE("queueBuffer: slot %d was queued without requesting " "a buffer" , slot); return BAD_VALUE; } ... item.mAcquireCalled = mSlots[slot].mAcquireCalled; item.mGraphicBuffer = mSlots[slot].mGraphicBuffer; item.mCrop = crop; item.mTransform = transform & ~static_cast<uint32_t>(NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY); item.mTransformToDisplayInverse = (transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0 ; item.mScalingMode = static_cast<uint32_t>(scalingMode); item.mTimestamp = requestedPresentTimestamp; item.mIsAutoTimestamp = isAutoTimestamp; item.mDataSpace = dataSpace; item.mHdrMetadata = hdrMetadata; item.mFrameNumber = currentFrameNumber; item.mSlot = slot; item.mFence = acquireFence; item.mFenceTime = acquireFenceTime; item.mIsDroppable = mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock || (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot); item.mSurfaceDamage = surfaceDamage; item.mQueuedBuffer = true ; item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh; item.mApi = mCore->mConnectedApi; mSlots[slot].mFence = acquireFence; mSlots[slot].mBufferState.queue(); if (mCore->mQueue.empty()) { mCore->mQueue.push_back(item); frameAvailableListener = mCore->mConsumerListener; }else { const BufferItem& last = mCore->mQueue.itemAt( mCore->mQueue.size() - 1 ); if (last.mIsDroppable) { ... mCore->mQueue.editItemAt(mCore->mQueue.size() - 1 ) = item; frameReplacedListener = mCore->mConsumerListener; }else { mCore->mQueue.push_back(item); frameAvailableListener = mCore->mConsumerListener; } } ... if (frameAvailableListener != NULL) { frameAvailableListener->onFrameAvailable(item); } else if (frameReplacedListener != NULL) { frameReplacedListener->onFrameReplaced(item); } }
//TODO 这里有个问题 如何和BufferLayer绑定
1 2 3 4 5 void BufferQueueLayer::onFrameAvailable (const BufferItem& item) { ... mFlinger->signalLayerUpdate(); }
1 2 3 4 5 6 void SurfaceFlinger::signalLayerUpdate () { mScheduler->resetIdleTimer(); mPowerAdvisor.notifyDisplayUpdateImminent(); mEventQueue->invalidate(); }
unlockAndPost()主要调用到queueBuffer()。
上节在dequeueBuffer()获取slot之后,就在对应的slot生成了GraphicBuffer。就可以继续Draw填充过程。
填充完成后,调用queueBuffer()根据slot获取对应的GraphicBuffer,封装成BufferItem对象,在回调onFrameAvailable()传入。通知BufferQueueConsumer有新数据传入。
BufferQueue
Android显示系统的核心 。遵循生产者-消费者模型,只要往BufferQueue填充数据,就被认为是生产者。从BufferQueue获取数据,就被认为是消费者。
SurfaceFlinger在合成并显示UI内容时,UI负责生产内容,SurfaceFlinger作为消费者消费内容。
在截屏时,SurfaceFlinger作为生产者,将当前的UI内容填充到另一个BufferQueue内,截屏作为消费者从BufferQueue获取数据
如图所示执行步骤如下所示:
初始化一个BufferQueue
BufferQueueProducer调用dequeueBuffer向BufferQueue申请一块空的GRaphicBuffer
可以通过requestBuffer获取对应的GraphicBuffer
向GraphicBuffer填充完数据后,调用queueBuffer向BufferQueue添加GraphicBuffer
添加数据完成后,BufferQueue通过回调通知消费者,有新数据加入——onFrameAvaliable()
BufferQueueConsumer调用acquireBuffer从BufferQueue获取GraphicBuffer
待GraphicBuffer使用完毕后,调用releaseBuffer将空的GraphicBuffer还给BufferQueue以便重复利用
空的数据返回后,BufferQueue通过回调通知生产者,有空闲数据。后续生产者可以继续获取空的GraphicBuffer进行使用——onBufferReleased()
在2~8之间循环,形成一整套图形数据的生产-消费过程。
GraphicBuffer–BufferState 上面有提到,调用dequeueBuffer()需要获取空的GraphicBuffer,通过getFreeBufferLocked()寻找。
其中GraphicBuffer有以下几种状态(BufferSlot.BufferState):
FREE:当前GraphicBuffer可用,且位于BufferQueue内
DEQUEUED:当前GraphicBuffer被生产者获取了,该buffer当前属于生产者
QUEUED:当前GraphicBuffer被生产者填充了数据,该buffer当前属于BufferQueue
ACQUIRED:当前GraphicBuffer被消费者获取了,该buffer当前属于消费者
硬件绘制
默认开启硬件加速,可以通过配置android:hardwareAccelerated="false"关闭硬件加速
把View中绘制的计算工作交给GPU来处理,就是把drawXX()相关的方法进行转换。
硬件绘制主要包含两步:
构建阶段
遍历所有View,将需要绘制的操作缓存下来,构建DisplayList。交给RenderThread使用GPU进行硬件加速渲染。
绘制阶段
构建好的DisplayList交给RenderThread使用GPU进行硬件加速渲染,绘制的内容保存在Graphic Buffer并交由SurfaceFlinger显示。
控制硬件加速
硬件绘制需要在开启硬件加速的条件下才可以执行
可以在以下级别控制硬件加速:
窗口Window
配置如下代码
1 2 3 getWindow().setFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
视图View
为单个视图停用硬件加速
1 myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null );
DisplayList
本质上是一个缓冲区 ,里面记录即将执行的绘制命令序列。
DisplayList的存在有两个好处:
在绘制下一帧时,若View没有发生变化,就不必执行相关绘制API,直接复用上次的DisplayList。
在绘制下一帧时,若View发生变化,但只是一些简单属性发生变化,就不需重建DisplayList,直接修改DisplayList相关属性即可。
针对以下属性,都不需重建DisplayList
alpha:更改层的不透明度
x、y、translationX、translationY:更改层的位置
scaleX、scaleY:更改层的大小
rotation、rotationX、rotationY:更改层在 3D 空间里的方向
pivotX、pivotY:更改层的转换原点
以上在使用DisplayList的过程都不需要执行onDraw()。
RenderNode
在Android 5.0后引入,是对DisplayList以及View显示属性的封装。
通常一个RenderNode对应一个View,包含了View自身及其子View的所有DisplayList。
其中还有一个RootRenderNode,里面包含着View层次结构中所有View的DisplayList信息。
ViewRootImpl硬件绘制相关
只有当前View支持硬件加速时,才可以进入硬件绘制
if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled())
ThreadedRenderer.draw()
ThreadedRenderer在UI线程创建,主要执行了两步:
构建View的DrawOp树,就是DisplayList。DrawOp 表示 Drawing Operations
与渲染线程(RenderThread)进行通信
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void draw (View view, AttachInfo attachInfo, DrawCallbacks callbacks, FrameDrawingCallback frameDrawingCallback) { attachInfo.mIgnoreDirtyState = true ; final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer; choreographer.mFrameInfo.markDrawStart(); updateRootDisplayList(view, callbacks); ... final long [] frameInfo = choreographer.mFrameInfo.mFrameInfo; if (frameDrawingCallback != null ) { nSetFrameCallback(mNativeProxy, frameDrawingCallback); } int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length); ... }
updateRootDisplayList()
构建DrawOp树,构建RootDisplayList
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 private void updateRootDisplayList (View view, DrawCallbacks callbacks) { updateViewTreeDisplayList(view); if (mRootNodeNeedsUpdate || !mRootNode.isValid()) { DisplayListCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight); try { final int saveCount = canvas.save(); canvas.translate(mInsetLeft, mInsetTop); callbacks.onPreDraw(canvas); canvas.insertReorderBarrier(); canvas.drawRenderNode(view.updateDisplayListIfDirty()); canvas.insertInorderBarrier(); callbacks.onPostDraw(canvas); canvas.restoreToCount(saveCount); mRootNodeNeedsUpdate = false ; } finally { mRootNode.end(canvas); } } }private void updateViewTreeDisplayList (View view) { view.mPrivateFlags |= View.PFLAG_DRAWN; view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) == View.PFLAG_INVALIDATED; view.mPrivateFlags &= ~View.PFLAG_INVALIDATED; view.updateDisplayListIfDirty(); view.mRecreateDisplayList = false ; }
DecorView.updateDisplayListIfDirty()
updateRootDisplayList()中对应的View就是DecorView,是所有View的顶层。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @NonNull public RenderNode updateDisplayListIfDirty () { ... if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || !renderNode.isValid() || (mRecreateDisplayList)) { ... final DisplayListCanvas canvas = renderNode.start(width, height); try { if (layerType == LAYER_TYPE_SOFTWARE) { buildDrawingCache(true ); Bitmap cache = getDrawingCache(true ); if (cache != null ) { canvas.drawBitmap(cache, 0 , 0 , mLayerPaint); } } else { if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { dispatchDraw(canvas); drawAutofilledHighlight(canvas); ... } else { draw(canvas); } } } finally { renderNode.end(canvas); setDisplayListProperties(renderNode); } } }
DecorView执行updateDisplayListIfDirty(),调用到draw(Canvas),然后向下递归调用到child.draw()
updateRootDisplayList()主要执行以下几步:
更新DecorView操作缓存(DisplayList)——updateViewTreeDisplayList(decorView)
利用DisplayCanvas构建并缓存所有的DrawOp(View的绘制操作)——mRootNode.start()
将DisplayListCanvas缓存的DrawOp填充到RenderNode(View)——View.updateDisplayListIfDirty()
将DecorView的缓存DrawOp填充到RootRenderNode中——mRootNode.end()
View硬件绘制相关 上一节中,通过DecorView递归调用子View.updateDisplayListIfDirty()不断填充DisplayList到对应View的RenderNode
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 public View (Context context) { ... mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this )); ... } boolean draw (Canvas canvas, ViewGroup parent, long drawingTime) { final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); boolean drawingWithRenderNode = mAttachInfo != null && mAttachInfo.mHardwareAccelerated && hardwareAcceleratedCanvas; ... if (drawingWithRenderNode) { renderNode = updateDisplayListIfDirty(); if (!renderNode.isValid()) { renderNode = null ; drawingWithRenderNode = false ; } } } public RenderNode updateDisplayListIfDirty () { final RenderNode renderNode = mRenderNode; if (!canHaveDisplayList()) { return renderNode; } if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || !renderNode.isValid() || (mRecreateDisplayList)) { if (renderNode.isValid() && !mRecreateDisplayList) { mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; dispatchGetDisplayList(); return renderNode; } mRecreateDisplayList = true ; int width = mRight - mLeft; int height = mBottom - mTop; int layerType = getLayerType(); final DisplayListCanvas canvas = renderNode.start(width, height); try { if (layerType == LAYER_TYPE_SOFTWARE) { buildDrawingCache(true ); Bitmap cache = getDrawingCache(true ); if (cache != null ) { canvas.drawBitmap(cache, 0 , 0 , mLayerPaint); } } else { computeScroll(); canvas.translate(-mScrollX, -mScrollY); mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { dispatchDraw(canvas); drawAutofilledHighlight(canvas); ... } else { draw(canvas); } } } finally { renderNode.end(canvas); setDisplayListProperties(renderNode); } } else { mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; } return renderNode; } public boolean canHaveDisplayList () { return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null ); } mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0 ;
根据上述源码可判断View需要重新构建DisplayList(执行draw())有以下条件:
(mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0当前View绘制缓存无效
mPrivateFlags没有PFLAG_DRAWING_CACHE_VALID标记
renderNode.isValid()==false View对应的DisplayList尚未构建或者被销毁
只要View绘制过一次,就会一直返回true。除非detached
mRecreateDisplayList==true View需要重新构建DisplayList
mPrivateFlags持有PFLAG_INVALIDATED标记
能满足以上条件的就是调用View.invalidate()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public void invalidate () { invalidate(true ); } public void invalidate (boolean invalidateCache) { invalidateInternal(0 , 0 , mRight - mLeft, mBottom - mTop, invalidateCache, true ); } void invalidateInternal (int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate) { ... if (invalidateCache) { mPrivateFlags |= PFLAG_INVALIDATED; mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; } }
dispatchGetDisplayList() 只会在不重建DisplayList情况下调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 protected void dispatchGetDisplayList () {} @Override protected void dispatchGetDisplayList () { final int count = mChildrenCount; final View[] children = mChildren; for (int i = 0 ; i < count; i++) { final View child = children[i]; if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null )) { recreateChildDisplayList(child); } } ... } private void recreateChildDisplayList (View child) { child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED) != 0 ; child.mPrivateFlags &= ~PFLAG_INVALIDATED; child.updateDisplayListIfDirty(); child.mRecreateDisplayList = false ; }
RenderThread渲染UI 构建完RootRenderNode的DisplayList——DrawOp树之后,就需要准备渲染。利用GPU将DisplayList绘制到屏幕上 。
ThreadedRenderer#nSyncAndFrame 构建DisplayList完毕后,向下执行到nSyncAndDrawFrame()
1 2 3 4 5 6 7 8 9 10 11 12 void draw (View view, AttachInfo attachInfo, DrawCallbacks callbacks, FrameDrawingCallback frameDrawingCallback) { ... updateRootDisplayList(view, callbacks); ... int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length); } private static native int nSyncAndDrawFrame (long nativeProxy, long [] frameInfo, int size) ;
nSyncAndDrawFrame()切换到Native层执行
1 2 3 4 5 6 7 8 9 10 static int android_view_ThreadedRenderer_syncAndDrawFrame (JNIEnv* env, jobject clazz, jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) { LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE, "Mismatched size expectations, given %d expected %d" , frameInfoSize, UI_THREAD_FRAME_INFO_SIZE); RenderProxy* proxy = reinterpret_cast <RenderProxy*>(proxyPtr); env->GetLongArrayRegion(frameInfo, 0 , frameInfoSize, proxy->frameInfo()); return proxy->syncAndDrawFrame(); }
通过RenderProxy继续执行
1 2 3 4 int RenderProxy::syncAndDrawFrame () { return mDrawFrameTask.drawFrame(); }
调用了DrawFrameTask#drawFrame()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 int DrawFrameTask::drawFrame () { LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!" ); mSyncResult = SyncResult::OK; mSyncQueued = systemTime(CLOCK_MONOTONIC); postAndWait(); return mSyncResult; }void DrawFrameTask::postAndWait () { AutoMutex _lock(mLock); mRenderThread->queue ().post([this ]() { run(); }); mSignal.wait(mLock); }void DrawFrameTask::run () { ATRACE_NAME("DrawFrame" ); bool canUnblockUiThread; bool canDrawThisFrame; { TreeInfo info (TreeInfo::MODE_FULL, *mContext) ; canUnblockUiThread = syncFrameState(info); canDrawThisFrame = info.out.canDrawThisFrame; if (mFrameCompleteCallback) { mContext->addFrameCompleteListener(std ::move(mFrameCompleteCallback)); mFrameCompleteCallback = nullptr ; } } CanvasContext* context = mContext; std ::function<void (int64_t )> callback = std ::move(mFrameCallback); mFrameCallback = nullptr ; if (canUnblockUiThread) { unblockUiThread(); } if (CC_UNLIKELY(callback)) { context->enqueueFrameWork([callback, frameNr = context->getFrameNumber()]() { callback(frameNr); }); } if (CC_LIKELY(canDrawThisFrame)) { context->draw(); } else { context->waitOnFences(); } if (!canUnblockUiThread) { unblockUiThread(); } }
主要执行过程为两步:
调用syncFrameState()同步Frame信息
调用CanvasContext.draw()开始绘制
syncFrameState 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 bool DrawFrameTask::syncFrameState (TreeInfo& info) { ATRACE_CALL(); int64_t vsync = mFrameInfo[static_cast <int >(FrameInfoIndex::Vsync)]; mRenderThread->timeLord().vsyncReceived(vsync); bool canDraw = mContext->makeCurrent(); mContext->unpinImages(); for (size_t i = 0 ; i < mLayers.size(); i++) { mLayers[i]->apply(); } mLayers.clear(); mContext->setContentDrawBounds(mContentDrawBounds); mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode); ... }
CanvasContext初始化
CanvasContext是 渲染的上下文,可以选择不同的渲染模式。
目前分为三种:
先分析CanvasContext#create()判断使用哪种渲染模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CanvasContext* CanvasContext::create (RenderThread& thread, bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) { auto renderType = Properties::getRenderPipelineType(); switch (renderType) { case RenderPipelineType::OpenGL: return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, std ::make_unique<OpenGLPipeline>(thread)); case RenderPipelineType::SkiaGL: return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, std ::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread)); case RenderPipelineType::SkiaVulkan: return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, std ::make_unique<skiapipeline::SkiaVulkanPipeline>(thread)); default : LOG_ALWAYS_FATAL("canvas context type %d not supported" , (int32_t )renderType); break ; } return nullptr ; }
就拿第一个OpenGLPipeline进行分析,其他的和他流程一致,不过绘制方式不同
OpenGLPipeline 1 2 3 OpenGLPipeline::OpenGLPipeline(RenderThread& thread) : mEglManager(thread.eglManager()), mRenderThread(thread) {}
创建了OpenGLPipeline之后,对应的也创建了EglManager对象。
EglManager
主要封装了 opengl相关的操作
初始化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 void EglManager::initialize () { if (hasEglContext()) return ; ATRACE_NAME("Creating EGLContext" ); mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s" , eglErrorString()); EGLint major, minor; initExtensions(); if (Properties::enablePartialUpdates) { if (Properties::useBufferAge && EglExtensions.bufferAge) { mSwapBehavior = SwapBehavior::BufferAge; } else { mSwapBehavior = SwapBehavior::Preserved; } } loadConfigs(); createContext(); createPBufferSurface(); makeCurrent(mPBufferSurface); DeviceInfo::initialize(); mRenderThread.renderState().onGLContextCreated();
目前只是创建了PBufferSurface,在没有WindowSurface的时候是无法渲染显示在屏幕上的。
PBufferSurface:在显存中开辟一块空间,存放渲染后的数据。
WindowSurface:在屏幕上的一块显示区域的封装,渲染后就显示在屏幕上
设置WindowSurface
主要是在ViewRootImpl#performTraversals()进行设置的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private void performTraversals () { ... if (mAttachInfo.mThreadedRenderer != null ) { try { hwInitialized = mAttachInfo.mThreadedRenderer.initialize( mSurface); if (hwInitialized && (host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0 ) { mSurface.allocateBuffers(); } } catch (OutOfResourcesException e) { handleOutOfResourcesException(e); return ; } } }
ThreadedRenderer#initalize
1 2 3 4 5 6 7 8 boolean initialize (Surface surface) throws OutOfResourcesException { boolean status = !mInitialized; mInitialized = true ; updateEnabledState(surface); nInitialize(mNativeProxy, surface); return status; }
切换到Native层继续执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 static void android_view_ThreadedRenderer_initialize (JNIEnv* env, jobject clazz, jlong proxyPtr, jobject jsurface) { RenderProxy* proxy = reinterpret_cast <RenderProxy*>(proxyPtr); sp<Surface> surface = android_view_Surface_getSurface(env, jsurface); proxy->initialize(surface); }void RenderProxy::initialize (const sp<Surface>& surface) { mRenderThread.queue ().post( [ this , surf = surface ]() mutable { mContext->setSurface(std ::move(surf)); }); }void CanvasContext::setSurface (sp<Surface>&& surface) { ATRACE_CALL(); mNativeSurface = std ::move(surface); ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::Srgb; bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode); mFrameNumber = -1 ; if (hasSurface) { mHaveNewSurface = true ; mSwapHistory.clear(); } else { mRenderThread.removeFrameCallback(this ); mGenerationID++; } }
此处的mRenderPipeline为上节的OpenGLPipeline
1 2 3 4 5 6 7 8 9 10 11 12 13 14 bool OpenGLPipeline::setSurface (Surface* surface, SwapBehavior swapBehavior, ColorMode colorMode) { if (mEglSurface != EGL_NO_SURFACE) { mEglManager.destroySurface(mEglSurface); mEglSurface = EGL_NO_SURFACE; } if (surface) { const bool wideColorGamut = colorMode == ColorMode::WideColorGamut; mEglSurface = mEglManager.createSurface(surface, wideColorGamut); } return false ; }
执行到createSurface()创建WindowSurface
1 2 3 4 5 6 EGLSurface EglManager::createSurface (EGLNativeWindowType window, bool wideColorGamut) { ... EGLSurface surface = eglCreateWindowSurface( mEglDisplay, wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs); return surface; }
到此创建WindowSurface完毕。
CanvasContext#draw 1 2 3 4 5 6 7 8 9 10 11 void CanvasContext::draw () { ... bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue, mContentDrawBounds, mOpaque, mWideColorGamut, mLightInfo, mRenderNodes, &(profiler())); bool didSwap = mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap); }
OpenGLPipeline#draw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 bool OpenGLPipeline::draw (const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, const BakedOpRenderer::LightInfo& lightInfo, const std ::vector <sp<RenderNode>>& renderNodes, FrameInfoVisualizer* profiler) { mEglManager.damageFrame(frame, dirty); bool drew = false ; auto & caches = Caches::getInstance(); FrameBuilder frameBuilder (dirty, frame.width(), frame.height(), lightGeometry, caches) ; frameBuilder.deferLayers(*layerUpdateQueue); layerUpdateQueue->clear(); frameBuilder.deferRenderNodeScene(renderNodes, contentDrawBounds); BakedOpRenderer renderer (caches, mRenderThread.renderState(), opaque, wideColorGamut, lightInfo) ; frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); ProfileRenderer profileRenderer (renderer) ; profiler->draw(profileRenderer); drew = renderer.didDraw(); caches.clearGarbage(); caches.pathCache.trim(); caches.tessellationCache.trim(); }
OpenGLPipeline#swapBuffers 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 bool OpenGLPipeline::swapBuffers (const Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool * requireSwap) { GL_CHECKPOINT(LOW); currentFrameInfo->markSwapBuffers(); *requireSwap = drew || mEglManager.damageRequiresSwap(); if (*requireSwap && (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty)))) { return false ; } return *requireSwap; }
根据图示渲染过程主要分为5阶段:
UI线程创建OpenGL渲染需要的命令及数据——构建DrawOp树
CPU将数据共享给GPU,使用匿名共享内存
通知GPU渲染
swapBuffers,并通知SurfaceFlinger开始合成图层
SurfaceFlinger开始合成图层
硬件绘制流程
如上图所示:
硬件绘制的流程,主要包含两个步骤:录制 、 回放 。
录制:需要View的draw()参与,需要记录View的绘制步骤,并编译为绘制指令 (drawOp)
回放:还原绘制内容,只需要还原绘制指令 ,而且这个绘制指令是可以修改的,修改的过程是不需要重新触发draw()。
硬件渲染过程
软件绘制VS硬件绘制
渲染场景
软件绘制
硬件绘制
效果分析
页面初始化
绘制所有View
创建所有DisplayList
GPU负责复杂的计算任务
调用背景透明TextView.setText()
重绘脏区所有View
TextView及每一级父View重建DisplayList
重叠的兄弟节点不需要进行重绘,GPU会自行处理
TextView逐帧播放动画
每帧动画都要重绘脏区View
第一帧需要重建DisplayList 后续只要更新对应的DisplayList即可
刷新每帧性能提升
修改TextView透明度
重绘脏区所有View
直接调用RenderNode.setAlpha()即可
只触发DecorView.updateDisplayListIfDirty,不再往下遍历
绘制缓存
绘图缓存是指一个Bitmap(软件绘制)和(硬件绘制),保存的是控件及其子控件的一个快照。
可以通过View.setLayerType()设置使用何种类型的缓存。
LAYER_TYPE_NONE:视图正常渲染,不受屏幕外缓冲区支持。默认值
LAYER_TYPE_SOFTWARE:标识这个View有一个Software Layer,在一定条件下,会变成bitmap对象。
LAYER_TYPE_HARDWARE:标识这个VIew有一个Hardware Layer,通过GPU来实现。依赖硬件加速实现,如果未开启硬件加速,按照Software Layer实现。
软件绘制缓存 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 boolean draw (Canvas canvas, ViewGroup parent, long drawingTime) { ... Bitmap cache = null ; int layerType = getLayerType(); if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { if (layerType != LAYER_TYPE_NONE) { layerType = LAYER_TYPE_SOFTWARE; buildDrawingCache(true ); } cache = getDrawingCache(true ); } } public void buildDrawingCache (boolean autoScale) { buildDrawingCacheImpl(autoScale); } private void buildDrawingCacheImpl (boolean autoScale) { ... quality = Bitmap.Config.ARGB_8888; bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), width, height, quality); bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); if (autoScale) { mDrawingCache = bitmap; } else { mUnscaledDrawingCache = bitmap; } ... }
要启用软件绘制缓存,必须调用View.setLayerType()设置LAYER_TYPE_HARDDWARE、LAYER_TYPE_SOFTWARE。通过buildDrawingCache()生成绘制缓存,对应会生成两个缓存对象:
mDrawingCache:根据兼容模式进行放大或缩小
mUnscaledDrawingCache:反映了控件的真实尺寸,多用作控件截图。
后续通过getDrawingCache()获取缓存内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 boolean draw (Canvas canvas, ViewGroup parent, long drawingTime) { final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; ... if (!drawingWithDrawingCache) { if (drawingWithRenderNode) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; ((DisplayListCanvas) canvas).drawRenderNode(renderNode); } else { if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; dispatchDraw(canvas); } else { draw(canvas); } } }else if (cache!=null ){ canvas.drawBitmap(cache...) } }
硬件绘制缓存 DisplayList可以理解为缓存,开启硬件加速时,只要每次回放DisplayList即可。
绘制缓存的开启原则
不要为十分轻量级的控件启用绘制缓存。可能缓存绘制的开销 > 控件重绘开销
为很少发生内容改变的控件启用绘制缓存。避免invalidate()时产生额外的缓存绘制操作
当父控件需要频繁改变子控件的位置或变换时对子控件启用绘制缓存,避免频繁重绘子控件。通过ViewGroup.setChildrenDrawingWithCache()启用子控件绘制缓存。
属性动画更新相关
在中讲到最后通过反射调用View.setXX()去执行动画。
1 2 3 4 5 6 7 8 9 10 11 12 public void setScaleX (float scaleX) { if (scaleX != getScaleX()) { scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX" ); invalidateViewProperty(true , false ); mRenderNode.setScaleX(scaleX); invalidateViewProperty(false , true ); invalidateParentIfNeededAndWasQuickRejected(); notifySubtreeAccessibilityStateChangedIfNeeded(); } }
关键在于invalidateViewProperty()调用界面刷新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 void invalidateViewProperty (boolean invalidateParent, boolean forceRedraw) { if (!isHardwareAccelerated() || !mRenderNode.isValid() || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0 ) { if (invalidateParent) { invalidateParentCaches(); } if (forceRedraw) { mPrivateFlags |= PFLAG_DRAWN; } invalidate(false ); } else { damageInParent(); } }protected void damageInParent () { if (mParent != null && mAttachInfo != null ) { mParent.onDescendantInvalidated(this , this ); } }
mParent一般指向ViewGroup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public void onDescendantInvalidated (@NonNull View child, @NonNull View target) { ... if ((target.mPrivateFlags & ~PFLAG_DIRTY_MASK) != 0 ) { mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY; mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; } ... if (mParent != null ) { mParent.onDescendantInvalidated(this , target); } }
在onDescendantInvalidated()主要移除了PFLAG_DRAWING_CACHE_VALID标志
最顶层的View是DecorView,而ViewRootImpl就是DecorView的parent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Override public void onDescendantInvalidated (@NonNull View child, @NonNull View descendant) { if ((descendant.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0 ) { mIsAnimating = true ; } invalidate(); } void invalidate () { mDirty.set(0 , 0 , mWidth, mHeight); if (!mWillDrawSoon) { scheduleTraversals(); } }
总结:属性动画最后反射调用View.setXX()更新View属性时,调用到invalidateViewProperty(),主要实现的功能就是移除PFLAG_DRAWING_CACHE_VALID标志。在执行绘制过程中,在回到View.updateDisplayListIfDirty()时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public RenderNode updateDisplayListIfDirty () { ... if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || !renderNode.isValid() || (mRecreateDisplayList)) { if (renderNode.isValid() && !mRecreateDisplayList) { mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; dispatchGetDisplayList(); return renderNode; } ... }
在开启硬件加速的条件下,属性动画更新过程中不会回调onDraw()
关键节点 DisplayList初始化DisplayListCanvas.start() -> DisplayListCanvas.obtain()->nCreateDisplayListCanvas
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 static jlong android_view_DisplayListCanvas_createDisplayListCanvas (jlong renderNodePtr, jint width , jint height ) { RenderNode* renderNode = reinterpret_cast <RenderNode*>(renderNodePtr); return reinterpret_cast <jlong>(Canvas::create_recording_canvas(width , height , renderNode)); }Canvas* Canvas::create_recording_canvas (int width , int height , uirenderer::RenderNode* renderNode) { if (uirenderer::Properties::isSkiaEnabled()) { return new uirenderer::skiapipeline::SkiaRecordingCanvas(renderNode, width , height ); } return new uirenderer::RecordingCanvas(width , height ); }bool Properties::isSkiaEnabled () { auto renderType = getRenderPipelineType(); return RenderPipelineType::SkiaGL == renderType || RenderPipelineType::SkiaVulkan == renderType; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 RecordingCanvas::RecordingCanvas(size_t width , size_t height ) : mState(*this ), mResourceCache(ResourceCache::getInstance()) { resetRecording(width , height ); }void RecordingCanvas::resetRecording (int width , int height , RenderNode* node) { LOG_ALWAYS_FATAL_IF(mDisplayList, "prepareDirty called a second time during a recording!" ); mDisplayList = new DisplayList(); mState.initializeRecordingSaveStack(width , height ); mDeferredBarrierType = DeferredBarrierType::InOrder; }
插入DrawOp到DisplayList DisplayListCanvas内部也包含了各种drawXX(),例如drawLines()、drawText()等。在调用这些方法后,会把对应的绘制操作转换为drawOp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public final class DisplayListCanvas extends RecordingCanvas { ... public void drawCircle (CanvasProperty<Float> cx, CanvasProperty<Float> cy, CanvasProperty<Float> radius, CanvasProperty<Paint> paint) { nDrawCircle(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(), radius.getNativeContainer(), paint.getNativeContainer()); } } @Override public final void drawLine (float startX, float startY, float stopX, float stopY, @NonNull Paint paint) { nDrawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance()); }
drawCircle()和drawRoundRect()由DisplayListCanvas实现。其他的绘制方法交由RecordingCanvas实现。
1 2 3 4 5 6 7 8 9 10 static void android_view_DisplayListCanvas_drawCircleProps (jlong canvasPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) { Canvas* canvas = reinterpret_cast <Canvas*>(canvasPtr); CanvasPropertyPrimitive* xProp = reinterpret_cast <CanvasPropertyPrimitive*>(xPropPtr); CanvasPropertyPrimitive* yProp = reinterpret_cast <CanvasPropertyPrimitive*>(yPropPtr); CanvasPropertyPrimitive* radiusProp = reinterpret_cast <CanvasPropertyPrimitive*>(radiusPropPtr); CanvasPropertyPaint* paintProp = reinterpret_cast <CanvasPropertyPaint*>(paintPropPtr); canvas->drawCircle(xProp, yProp, radiusProp, paintProp); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 virtual void drawLine (float startX, float startY, float stopX, float stopY, const SkPaint& paint) override { float points[4 ] = {startX, startY, stopX, stopY}; drawLines(points, 4 , paint); }void RecordingCanvas::drawLines (const float * points, int floatCount, const SkPaint& paint) { if (CC_UNLIKELY(floatCount < 4 || paint.nothingToDraw())) return ; floatCount &= ~0x3 ; addOp(alloc().create_trivial<LinesOp>( calcBoundsOfPoints(points, floatCount), *mState.currentSnapshot()->transform, getRecordedClip(), refPaint(&paint), refBuffer<float >(points, floatCount), floatCount)); }
通过addOp()将DrawLine的绘制操作缓存到displayList。
参考链接 View的绘制过程
Android官方文档-硬件加速
DisplayList构建过程分析
Android硬件加速原理与实现简介
RenderThread与OpenGL GPU渲染
Android 中的 Hardware Layer 详解
深入浅出Android BufferQueue
BufferQueue