软硬件绘制的分歧点 绘制过程入口位于ViewRootImpl.performDraw()
中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //viewRootImpl.java private void performDraw() { ... try { //调用draw()执行实际的绘制工作 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 //ViewRootImpl.javaprivate 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) { // Draw with software renderer. final Canvas canvas; canvas = mSurface.lockCanvas(dirty);//获取用于绘制的Canvas ... mView.draw(canvas);//将mView的内容绘制到Canvas ... //将Canvas的内容显示到屏幕上,向SurfaceFlinger服务Queue一个Graphic Buffer surface.unlockCanvasAndPost(canvas); }
此处的mView
对应的就是DecorView
1 2 3 4 5 6 7 8 9 //DecorView.java @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 //View.java public void draw(Canvas canvas) { ... if (!dirtyOpaque) { //绘制背景 drawBackground(canvas); } //绘制自身 if (!dirtyOpaque) onDraw(canvas); //绘制子View 只有ViewGroup会实现该方法 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 //ViewGroup.java protected void dispatchDraw(Canvas canvas) { ... final ArrayList<View> preorderedList = usingRenderNodeProperties ? null : buildOrderedChildList();//绘制顺序按照Z值从大到小排列 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);//根据自定义顺序获取当前绘制的View的绘制顺序 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null ) { more |= drawChild(canvas, child, drawingTime); } } } //绘制子View 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 //View.javaboolean 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) { // If not drawing with RenderNode, treat HW layers as SW 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 { // ViewGroup 不需要绘制背景直接 绘制子View 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 //View.java 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 //ViewRootImpl.java canvas = mSurface.lockCanvas() //Surface.java public Canvas lockCanvas(Rect inOutDirty) throws Surface.OutOfResourcesException, IllegalArgumentException { synchronized (mLock) { checkNotReleasedLocked(); if (mLockedObject != 0) { // Ideally, nativeLockCanvas() would throw in this situation and prevent the // double -lock, but that won't happen if mNativeObject was updated. We can't // abandon the old mLockedObject because it might still be in use, so instead // we just refuse to re-lock the Surface. throw new IllegalArgumentException("Surface was already locked"); } mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty); return mCanvas; } }
执行到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 // core/jni/android_view_Surface.cppstatic jlong nativeLockCanvas(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) { sp<Surface> surface(reinterpret_cast <Surface *>(nativeObject)); ... //申请buffer ANativeWindow_Buffer outBuffer; status_t err = surface->lock(&outBuffer, dirtyRectPtr); ... //构建Bitmap对象 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 { // be safe with an empty bitmap. bitmap.setPixels(NULL ); } //canvas设置bitmap 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 //native/libs/gui/Surface.cpp 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); ... } //返回GraphicBuffer 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 //native/libs/gui/Surface.cppint 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 *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 //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) { ... while (found == BufferItem::INVALID_BUFFER_SLOT) { //找到可用的slot,并指定状态为FREE slot:BufferSlot——用来存储GraphicBuffer 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 ; //转化可用slot的GraphicBuffer状态为DEQUEUED 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); //对应outSlot申请GraphicBuffer 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 in shared buffer mode and a shared buffer exists, always // return it. if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = mCore->mSharedBufferSlot; } else { if (caller == FreeSlotCaller::Dequeue) { // If we're calling this from dequeue, prefer free buffers //寻找处于 FREE 状态的GraphicBuffer int slot = getFreeBufferLocked(); if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = slot; } else if (mCore->mAllowAllocation) { *found = getFreeSlotLocked(); } } else { // If we're calling this from attach, prefer free slots int slot = getFreeSlotLocked(); if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = slot; } else { *found = getFreeBufferLocked(); } } } } ... tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || tooManyBuffers; if (tryAgain) { //找不到可用的slot或者buffer太多,需要等待空闲 } }
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 //Surface.java 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 // core/jni/android_view_Surface.cppstatic void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj) { ... // 绘制完成后,将Canvas从surface上脱离 Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj); nativeCanvas->setBitmap(SkBitmap()); // unlock surface status_t err = surface->unlockAndPost(); if (err < 0) { doThrowIAE(env); } }
1 2 3 4 5 6 7 8 9 10 11 12 //native/libs/gui/Surface.cpp 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 //native/libs/gui/Surface.cppint Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { ... //根据Buffer获取slot int i = getSlotFromBufferLocked(buffer); ... //GraphicBufferQueue 插入 GraphicBuffer status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); ... //插入Buffer后通知 mQueueBufferCondition.broadcast(); } //根据传入buffer获取slotint Surface::getSlotFromBufferLocked( android_native_buffer_t* buffer) const { //NUM_BUFFER_SLOTS 64 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 //native /libs/gui/BufferQueueProducer.cpp status_t BufferQueueProducer::queueBuffer(int slot, const QueueBufferInput &input, QueueBufferOutput *output) { BufferItem item; ... //判断slot 以及 buffer状态是否正常 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; } ... //构建BufferItem对象,等待传递 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; //切换 BufferSlot状态到 QUEUED mSlots[slot].mFence = acquireFence; mSlots[slot].mBufferState.queue(); //将item插入队列 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; } } ... //回调frameAvaliableListener 通知消费者有数据入队了 if (frameAvailableListener != NULL) { frameAvailableListener->onFrameAvailable(item); } else if (frameReplacedListener != NULL) { frameReplacedListener->onFrameReplaced(item); } }
//TODO 这里有个问题 如何和BufferLayer
绑定
1 2 3 4 5 //native/services/surfaceflinger/BufferLayer.cppvoid BufferQueueLayer::onFrameAvailable(const BufferItem& item) { ... mFlinger->signalLayerUpdate(); }
1 2 3 4 5 6 //SurfaceFlinger.cppvoid 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 //ThreadedRenderer.java void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks, FrameDrawingCallback frameDrawingCallback) { attachInfo.mIgnoreDirtyState = true ; final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer; choreographer.mFrameInfo.markDrawStart(); //构建View的DrawOp树 updateRootDisplayList(view, callbacks); ... final long [] frameInfo = choreographer.mFrameInfo.mFrameInfo; if (frameDrawingCallback != null ) { nSetFrameCallback(mNativeProxy, frameDrawingCallback); } //通知RenderThread线程绘制 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) { //更新View的displayList updateViewTreeDisplayList(view); if (mRootNodeNeedsUpdate || !mRootNode.isValid()) { //获取DisplayCanvas DisplayListCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight); try { final int saveCount = canvas.save(); canvas.translate(mInsetLeft, mInsetTop); callbacks.onPreDraw(canvas); canvas.insertReorderBarrier(); //displayListCanvas缓存View对应的drawOp节点 canvas.drawRenderNode(view.updateDisplayListIfDirty()); canvas.insertInorderBarrier(); callbacks.onPostDraw(canvas); canvas.restoreToCount(saveCount); mRootNodeNeedsUpdate = false ; } finally { //RootRenderNode填充所有节点 mRootNode.end(canvas); } } }private void updateViewTreeDisplayList(View view) { view.mPrivateFlags |= View.PFLAG_DRAWN; view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)//invalidate()对应标记 == View.PFLAG_INVALIDATED;//初始DecorView默认为 true 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 //View.java @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 { // Fast path for layouts with no backgrounds //ViewGroup不需要绘制,直接调用dispatchDraw if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { dispatchDraw(canvas); drawAutofilledHighlight(canvas); ... } else { //ViewGroup(需要绘制) / View 直接调用draw 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 //View.javapublic 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) { //继续执行到updateDisplayListIfDirty renderNode = updateDisplayListIfDirty(); if (!renderNode.isValid()) { renderNode = null ; drawingWithRenderNode = false ; } } } public RenderNode updateDisplayListIfDirty() { final RenderNode renderNode = mRenderNode; if (!canHaveDisplayList()) { // can't populate RenderNode, don't try return renderNode; } if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 //绘制缓存无效 || !renderNode.isValid() //渲染节点没有DisplayList || (mRecreateDisplayList)) { //需要刷新DisplayList // Don't need to recreate the display list, just need to tell our // children to restore/recreate theirs if (renderNode.isValid() //只要draw过一次后,一直返回true && !mRecreateDisplayList) {//调用一些只需要displayList属性修改的方法 //不需要重建 DisplayList mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; dispatchGetDisplayList(); return renderNode; // no work needed } // If we got here, we're recreating it. Mark it as such to ensure that // we copy in child display lists into ours in drawChild() mRecreateDisplayList = true ; int width = mRight - mLeft; int height = mBottom - mTop; int layerType = getLayerType(); //获取DisplayListCanvas 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; //ViewGroup不需要绘制,直接调用dispatchDraw if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { dispatchDraw(canvas); drawAutofilledHighlight(canvas); ... } else { //ViewGroup(需要绘制) / View 直接调用draw draw(canvas); } } } finally { //RenderNode 收集DisplayList renderNode.end(canvas); setDisplayListProperties(renderNode); } } else { mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; } return renderNode; } //是否会有DisplayList = 是否开启硬件加速 public boolean canHaveDisplayList() { return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null ); } //只有flag标记为 PFLAG_INVALIDATED ,调用需要 重建DisplayList 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 //View.java 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; //添加PFLAG_INVALIDATED标志 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;//移除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 //View.java // 只会在ViewGroup下实现,更新子View的DisplayList protected void dispatchGetDisplayList() {} //ViewGroup.java @Override protected void dispatchGetDisplayList() { final int count = mChildrenCount; final View[] children = mChildren; for (int i = 0; i < count; i++) { final View child = children[i]; //View可见 || 设置动画 if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null )) { recreateChildDisplayList(child);//调用子 } } ... } private void recreateChildDisplayList(View child) { child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED) != 0;//没有PFLAG_INVALIDATED 返回true child.mPrivateFlags &= ~PFLAG_INVALIDATED; //移除 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 //ThreadedRenderer.java void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks, FrameDrawingCallback frameDrawingCallback) { ... //构建DisplayList updateRootDisplayList(view, callbacks); ... //开始绘制DisplayList 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 //core/jni/android_view_ThreadedRenderer.cppstatic 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 //libs/hwui/renderthread/RenderProxy.cppint 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 //libs/hwui/renderthread/DrawFrameTask.cppint 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 ; } } // Grab a copy of everything we need CanvasContext* context = mContext; std ::function<void (int64_t)> callback = std ::move(mFrameCallback); mFrameCallback = nullptr ; // From this point on anything in "this " is *UNSAFE TO ACCESS* if (canUnblockUiThread) { unblockUiThread(); } // Even if we aren't drawing this vsync pulse the next frame number will still be accurate if (CC_UNLIKELY(callback)) { context->enqueueFrameWork([callback, frameNr = context->getFrameNumber()]() { callback(frameNr); }); } if (CC_LIKELY(canDrawThisFrame)) { //执行绘制流程 context->draw(); } else { // wait on fences so tasks don't overlap next frame 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 //libs/hwui/renderthread/OpenGLPipeline.cpp 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"); //获取EglDisplay对象 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(); // Now that extensions are loaded, pick a swap behavior if (Properties::enablePartialUpdates) { // An Adreno driver bug is causing rendering problems for SkiaGL with // buffer age swap behavior (b/31957043). To temporarily workaround, // we will use preserved swap behavior. if (Properties::useBufferAge && EglExtensions.bufferAge) { mSwapBehavior = SwapBehavior::BufferAge; } else { mSwapBehavior = SwapBehavior::Preserved; } } loadConfigs(); //创建egl上下文你 createContext(); //创建离屏渲染Buffer 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 //ViewRootImpl.java private void performTraversals() { ... if (mAttachInfo.mThreadedRenderer != null ) { try { //初始化ThreadedRenderer 并赋值surface 用于绘制显示 hwInitialized = mAttachInfo.mThreadedRenderer.initialize( mSurface); if (hwInitialized && (host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) { // Don't pre-allocate if transparent regions // are requested as they may not be needed 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); } //RenderProxy.cppvoid RenderProxy::initialize(const sp<Surface>& surface) { mRenderThread.queue ().post( [ this , surf = surface ]() mutable { mContext->setSurface(std ::move(surf)); }); } //CanvasContext.cppvoid 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 //libs/hwui/renderthread/OpenGLPipeline.cppbool 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); //调用GPU进行渲染 drew = renderer.didDraw(); // post frame cleanup 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); // Even if we decided to cancel the frame, from the perspective of jank // metrics the frame was swapped at this point 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 //View.java boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { ... Bitmap cache = null ; int layerType = getLayerType(); // layerType默认为LAYER_TYPE_NONE if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) {//软件绘制条件 if (layerType != LAYER_TYPE_NONE) {//必须设置 `LAYER_TYPE_SOFTWARE` 或 LAYER_TYPE_HARDWARE 缓存生效 // If not drawing with RenderNode, treat HW layers as SW layerType = LAYER_TYPE_SOFTWARE;//设置 软件layer buildDrawingCache(true );//构建缓存 } cache = getDrawingCache(true ); } } public void buildDrawingCache(boolean autoScale) { buildDrawingCacheImpl(autoScale); } private void buildDrawingCacheImpl(boolean autoScale) { ... quality = Bitmap.Config.ARGB_8888;//默认缓存bitmap图像类型 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 //View.javaboolean 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 {//软件绘制 // 需要回调到`onDraw()` 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 //view.java public void setScaleX(float scaleX) { if (scaleX != getScaleX()) { scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX"); invalidateViewProperty(true , false ); mRenderNode.setScaleX(scaleX);//更新对应View的displayList 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; // force another invalidation with the new orientation } 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 //ViewGroup.java public void onDescendantInvalidated(@NonNull View child, @NonNull View target) { ... if ((target.mPrivateFlags & ~PFLAG_DIRTY_MASK) != 0) { // We lazily use PFLAG_DIRTY, since computing opaque isn't worth the potential // optimization in provides in a DisplayList world. mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY; // simplified invalidateChildInParent behavior: clear cache validity to be safe... //标记缓存无效 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; } ... if (mParent != null ) { //继续向顶层View请求 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 //ViewRootImpl.java @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)) { // Don't need to recreate the display list, just need to tell our // children to restore/recreate theirs if (renderNode.isValid() && !mRecreateDisplayList) {//未设置 PFLAG_INVALIDATED标志 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; dispatchGetDisplayList();//只要刷新DisplayList return renderNode; // no work needed } ... }
在开启硬件加速的条件下,属性动画更新过程中不会回调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 //android_view_DisplayListCanvas.cppstatic 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.cpp 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); } //Properrties.cppbool Properties::isSkiaEnabled() { auto renderType = getRenderPipelineType();//分为三种类型 SkiaGL SkiaVulkan OpenGL(默认) return RenderPipelineType::SkiaGL == renderType || RenderPipelineType::SkiaVulkan == renderType; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 //RecordingCanvas.cpp 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();//初始化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 //DisplayListCanvas.javapublic final class DisplayListCanvas extends RecordingCanvas { ... //所有绘制方法由RecordCanvas实现 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()); } } //RecordingCanvas.java @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 //android_view_DisplayListCanvas.cppstatic 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 //RecordingCanvas.h 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); } //RecordingCanvas.cppvoid RecordingCanvas::drawLines(const float * points, int floatCount, const SkPaint& paint) { if (CC_UNLIKELY(floatCount < 4 || paint.nothingToDraw())) return ; floatCount &= ~0x3; // round down to nearest four 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