Android DisplayList机制浅析

Android3.0后可以在UI线程使用OpenGL达成支持硬件加速的Canvas的目的,当GUI框架接收到View重绘的请求后,框架跟之前一样,回调View的onDraw方法,并传入一个Canvas,但是跟之前不同的是,这个Canvas只是用于记录View的绘图指令到View本身的DisplayList中,并没有真正执行。
  1. 每个View拥有自己的DisplayList,DisplayList本身也构成一个树状的结构,跟View Hierachy保持一致;
  2. 当整个View Hierachy的DisplayList树都更新完毕后,框架就会执行该DisplayList树(status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level)),所谓执行,实际上就是把缓存的2D Canvas绘图指令转换成OpenGL的方法,最后调用glSwap执行OpenGL命令更新当前缓存,并切换前后缓存;
  3. Android 4.1后,DisplayList支持属性,如果View的一些属性发生变化(比如Scale),框架只是简单改变View的DisplayList的属性,而不需要调用View的onDraw方法重新生成新的DisplayList;
  4. DisplayList中可以嵌入Functor,Functor是一个用于回调的函数子,DisplayList把嵌入的Functor也当作一条绘图指令缓存起来(DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty)),在执行时直接调用Functor(status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty));
  5. DisplayList的执行可以有不同的返回结果,在4.1上,Done表示不再需要重新执行DisplayList,而Draw表示需要重新执行DisplayList(重现执行一次窗口重绘,但是不需要更新DisplayList,因为没有View被设置为dirty),Invoke是专门针对Functor而言的(4.1新增),如果Functor的执行返回Invoke,该Functor会被加入一个队列中,框架在执行完DisplayList后,马上会发起一个延迟调用,把队列里面的Functor再执行一遍(private void HardwareRenderer::handleFunctorStatus(View.AttachInfo attachInfo, int status)),执行的结果如果是Draw或者Invoke则继续处理直到Done为止;
  6. DisplayList的执行在4.0返回结果只有true和false,false等于Done,true相当于Draw;

status_t DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
// Ignore dirty during recording, it matters only when we replay
addOp(DisplayList::DrawGLFunction);
addInt((int) functor);
return DrawGlInfo::kStatusDone; // No invalidate needed at record-time

}
status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
interrupt();
detachFunctor(functor);

if (mDirtyClip) {
setScissorFromClip();
}

Rect clip(*mSnapshot->clipRect);
clip.snapToPixelBoundaries();

#if RENDER_LAYERS_AS_REGIONS
// Since we don’t know what the functor will draw, let’s dirty
// tne entire clip region
if (hasLayer()) {
dirtyLayerUnchecked(clip, getRegion());
}
#endif

DrawGlInfo info;
info.clipLeft = clip.left;
info.clipTop = clip.top;
info.clipRight = clip.right;
info.clipBottom = clip.bottom;
info.isLayer = hasLayer();
info.width = getSnapshot()->viewport.getWidth();
info.height = getSnapshot()->height;
getSnapshot()->transform->copyTo(&info.transform[0]);

status_t result = (*functor)(DrawGlInfo::kModeDraw, &info) | DrawGlInfo::kStatusDrew;

if (result != DrawGlInfo::kStatusDone) {
Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
dirty.unionWith(localDirty);

if (result & DrawGlInfo::kStatusInvoke) {
mFunctors.add(functor);
}
}

resume();
return result;
}

        private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
// If the draw flag is set, functors will be invoked while executing
// the tree of display lists
if ((status & DisplayList.STATUS_DRAW) != 0) {
if (mRedrawClip.isEmpty()) {
attachInfo.mViewRootImpl.invalidate();
} else {
attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
mRedrawClip.setEmpty();
}
}

if ((status & DisplayList.STATUS_INVOKE) != 0) {
scheduleFunctors(attachInfo, true);
}
}

        private void scheduleFunctors(View.AttachInfo attachInfo, boolean delayed) {
mFunctorsRunnable.attachInfo = attachInfo;
if (!attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
// delay the functor callback by a few ms so it isn’t polled constantly
attachInfo.mHandler.postDelayed(mFunctorsRunnable,
delayed ? FUNCTOR_PROCESS_DELAY : 0);
}
}
        class FunctorsRunnable implements Runnable {
View.AttachInfo attachInfo;

@Override
public void run() {
final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
if (renderer == null || !renderer.isEnabled() || renderer != GlRenderer.this) {
return;
}

final int surfaceState = checkCurrent();
if (surfaceState != SURFACE_STATE_ERROR) {
int status = mCanvas.invokeFunctors(mRedrawClip);
handleFunctorStatus(attachInfo, status);
}
}
}

status_t OpenGLRenderer::invokeFunctors(Rect& dirty) {
status_t result = DrawGlInfo::kStatusDone;
size_t count = mFunctors.size();

if (count > 0) {
SortedVector<Functor*> functors(mFunctors);
mFunctors.clear();

DrawGlInfo info;
info.clipLeft = 0;
info.clipTop = 0;
info.clipRight = 0;
info.clipBottom = 0;
info.isLayer = false;
info.width = 0;
info.height = 0;
memset(info.transform, 0, sizeof(float) * 16);

for (size_t i = 0; i < count; i++) {
Functor* f = functors.itemAt(i);
result |= (*f)(DrawGlInfo::kModeProcess, &info);

if (result & DrawGlInfo::kStatusDraw) {
Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
dirty.unionWith(localDirty);
}

if (result & DrawGlInfo::kStatusInvoke) {
mFunctors.add(f);
}
}
}

mCaches.activeTexture(0);

return result;
}