Android硬件加速

Android硬件加速xmind

软硬件绘制的分歧点

绘制过程入口位于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.java
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;
}
}
...
}
...

}

软件绘制

Android绘制-软件绘制

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()childView

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
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) {
// 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绘制流程

软件绘制-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.cpp
static 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.cpp
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
*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,并完成GraphicBufferBufferSlot的关联,途中切换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.cpp
static 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.cpp
int 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获取slot
int 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.cpp
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
...
mFlinger->signalLayerUpdate();
}
1
2
3
4
5
6
//SurfaceFlinger.cpp
void SurfaceFlinger::signalLayerUpdate() {
mScheduler->resetIdleTimer();
mPowerAdvisor.notifyDisplayUpdateImminent();
mEventQueue->invalidate();
}

unlockAndPost()主要调用到queueBuffer()

上节在dequeueBuffer()获取slot之后,就在对应的slot生成了GraphicBuffer。就可以继续Draw填充过程。

填充完成后,调用queueBuffer()根据slot获取对应的GraphicBuffer,封装成BufferItem对象,在回调onFrameAvailable()传入。通知BufferQueueConsumer有新数据传入。

img

BufferQueue

Android显示系统的核心。遵循生产者-消费者模型,只要往BufferQueue填充数据,就被认为是生产者。从BufferQueue获取数据,就被认为是消费者

SurfaceFlinger在合成并显示UI内容时,UI负责生产内容,SurfaceFlinger作为消费者消费内容。

在截屏时,SurfaceFlinger作为生产者,将当前的UI内容填充到另一个BufferQueue内,截屏作为消费者BufferQueue获取数据

img

如图所示执行步骤如下所示:

  1. 初始化一个BufferQueue
  2. BufferQueueProducer调用dequeueBufferBufferQueue申请一块空的GRaphicBuffer
  3. 可以通过requestBuffer获取对应的GraphicBuffer
  4. GraphicBuffer填充完数据后,调用queueBufferBufferQueue添加GraphicBuffer
  5. 添加数据完成后,BufferQueue通过回调通知消费者,有新数据加入——onFrameAvaliable()
  6. BufferQueueConsumer调用acquireBufferBufferQueue获取GraphicBuffer
  7. GraphicBuffer使用完毕后,调用releaseBuffer将空的GraphicBuffer还给BufferQueue以便重复利用
  8. 空的数据返回后,BufferQueue通过回调通知生产者,有空闲数据。后续生产者可以继续获取空的GraphicBuffer进行使用——onBufferReleased()
  9. 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显示。

控制硬件加速

硬件绘制-控制硬件加速

硬件绘制需要在开启硬件加速的条件下才可以执行

可以在以下级别控制硬件加速

  • 应用

    AndroidManifest.xml配置如下属性

    1
    <application android:hardwareAccelerated="true" ...>
  • Activity

    AndroidManifest.xml配置如下属性

    1
    2
    3
    4
    <application android:hardwareAccelerated="true">
    <activity ... />
    <activity android:hardwareAccelerated="false" /> //控制某个Activity关闭硬件加速
    </application>
  • 窗口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

本质上是一个缓冲区,里面记录即将执行的绘制命令序列

DisplayList的存在有两个好处:

  1. 在绘制下一帧时,若View没有发生变化,就不必执行相关绘制API,直接复用上次的DisplayList

  2. 在绘制下一帧时,若View发生变化,但只是一些简单属性发生变化,就不需重建DisplayList,直接修改DisplayList相关属性即可。

    针对以下属性,都不需重建DisplayList

    • alpha:更改层的不透明度
    • xytranslationXtranslationY:更改层的位置
    • scaleXscaleY:更改层的大小
    • rotationrotationXrotationY:更改层在 3D 空间里的方向
    • pivotXpivotY:更改层的转换原点

以上在使用DisplayList的过程都不需要执行onDraw()

img

RenderNode

在Android 5.0后引入,是对DisplayList以及View显示属性的封装。

通常一个RenderNode对应一个View,包含了View自身及其子View的所有DisplayList。

其中还有一个RootRenderNode,里面包含着View层次结构中所有View的DisplayList信息

ViewRootImpl硬件绘制相关

只有当前View支持硬件加速时,才可以进入硬件绘制

if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled())

硬件绘制-构建DisplayList

ThreadedRenderer.draw()

ThreadedRenderer在UI线程创建,主要执行了两步:

  • 构建View的DrawOp树,就是DisplayListDrawOp 表示 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()

硬件绘制-updateDisplayListIfDirty()

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.java
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) {
//继续执行到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())有以下条件:

  1. (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0当前View绘制缓存无效

    mPrivateFlags没有PFLAG_DRAWING_CACHE_VALID标记

  2. renderNode.isValid()==false View对应的DisplayList尚未构建或者被销毁

    只要View绘制过一次,就会一直返回true。除非detached

  3. 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

构建完RootRenderNodeDisplayList——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.cpp
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
//libs/hwui/renderthread/RenderProxy.cpp
int RenderProxy::syncAndDrawFrame() {
return mDrawFrameTask.drawFrame();
}

DrawFrameTask#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.cpp
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;
}
}

// 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是 渲染的上下文,可以选择不同的渲染模式。

目前分为三种:

  • OpenGL
  • SkiaGL
  • SkiaVulkan

先分析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.cpp
void RenderProxy::initialize(const sp<Surface>& surface) {
mRenderThread.queue().post(
[ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); });
}

//CanvasContext.cpp
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
//libs/hwui/renderthread/OpenGLPipeline.cpp
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);
//调用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;
}

img

根据图示渲染过程主要分为5阶段:

  1. UI线程创建OpenGL渲染需要的命令及数据——构建DrawOp树
  2. CPU将数据共享给GPU,使用匿名共享内存
  3. 通知GPU渲染
  4. swapBuffers,并通知SurfaceFlinger开始合成图层
  5. SurfaceFlinger开始合成图层

硬件绘制流程

硬件绘制流程

如上图所示:

硬件绘制的流程,主要包含两个步骤:录制 、 回放

录制:需要View的draw()参与,需要记录View的绘制步骤,并编译为绘制指令(drawOp)

回放:还原绘制内容,只需要还原绘制指令,而且这个绘制指令是可以修改的,修改的过程是不需要重新触发draw()

硬件渲染过程

RenderThread渲染过程

软件绘制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.java
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 {//软件绘制
// 需要回调到`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()启用子控件绘制缓存。

属性动画更新相关

Android绘制-属性动画更新相关

在中讲到最后通过反射调用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.cpp
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.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.cpp
bool 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.java
public 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.cpp
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
//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.cpp
void 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


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!