SurfaceFlinger学习笔记(五)之HWUI

关于Surface请参考下面文章
SurfaceFlinger学习笔记(一)应用启动流程
SurfaceFlinger学习笔记(二)之Surface
SurfaceFlinger学习笔记(三)之SurfaceFlinger进程
SurfaceFlinger学习笔记(四)之HWC2
SurfaceFlinger学习笔记(五)之HWUI
SurfaceFlinger学习笔记(六)之View Layout Draw过程分析


HWUI

渲染机制的更新,Android提出了硬件加速的机制,其作用就是将2D的绘图操纵,转换为对应的3D的绘图操纵,这个转换的过程,我们把它叫做录制。需要显示的时候,再用OpenGLES通过GPU去渲染。界面创建时,第一次全部录制,后续的过程中,界面如果只有部分区域的widget更新,只需要重新录制更新的widget。录制好的绘图操纵,保存在一个显示列表DisplayList中,需要真正显示到界面的时候,直接显示DisplayList中的绘图 操纵。这样,一方面利用GPU去渲染,比Skia要快;另一方面,采用DisplayList,值重新录制,有更新区域,最大程度利用上一帧的数据,效率自然就快很多。这就是硬件加速的来源

这个是Android原生的测试硬件绘制的应用

* frameworks/base/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java

public class HardwareCanvasSurfaceViewActivity extends Activity implements Callback {
    private SurfaceView mSurfaceView;
    private HardwareCanvasSurfaceViewActivity.RenderingThread mThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
     ...
        mSurfaceView = new SurfaceView(this);
        mSurfaceView.getHolder().addCallback(this);
     ...
    }
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mThread = new RenderingThread(holder);
        mThread.start();
    }
	...
    private static class RenderingThread extends Thread {
        private final SurfaceHolder mSurface;
        private volatile boolean mRunning = true;
        private int mWidth, mHeight;

        public RenderingThread(SurfaceHolder surface) {
            mSurface = surface;
        }
        ...
        @Override
        public void run() {
            ...
            while (mRunning && !Thread.interrupted()) {
                final Canvas canvas = mSurface.lockHardwareCanvas();
                try {
                    canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
                    canvas.drawRect(x, y, x + 20.0f, y + 20.0f, paint);
                } finally {
                    mSurface.unlockCanvasAndPost(canvas);
                }
			...
            }
        }
        void stopRendering() {
            interrupt();
            mRunning = false;
        }
    }
}

应用这里拿到一个Surface,然后lock一个HardwareCanvas,用lock的HardwareCanvas进行绘制,我们绘制的就可以使用硬件GPU进行绘制

初始化流程

  • step1:

SurfaceView
SurfaceView::lockHardwareCanvas调用Surface::lockHardwareCanvas
在Surface::lockHardwareCanvas中创建mHwuiContext ,然后调用mHwuiContext.lockCanvas

SurfaceView中里面实现了SurfaceHolder,并通过回调到activity等类,维护了一个callback的list,在updateSurface时候调用surfaceCreated、surfaceChanged,并包含成员Surface、SurfaceControl、SurfaceSession,mSurfaceControl通过new SurfaceControl.Builder(SurfaceSession)获取

SurfaceSession:定义在frameworks/base/core/java/android/view/SurfaceSession.java
frameworks/base/core/jni/android_view_SurfaceSession.cpp
为SurfaceComposerClient的封装,java层保存了SurfaceComposerClient的指针,通过调用jni的nativeCreate、nativeDestroy、nativeKill方法,native层调用
SurfaceComposerClient
client = reinterpret_cast(ptr);
client->decStrong((void*)nativeCreate);

Surface:定义在frameworks/base/core/java/android/view/Surface.java
作用:继承自Parcelable实现序列化,里面有个内部类 HwuiContext,在HwuiContext的构造函数中,创建了一个RenderNode和HwuiRenderer。HwuiRenderer为long,通过调用native方法nHwuiCreate。这里的HwuiContext,就是和HWUI打交道了

SurfaceFlinger学习笔记(五)之HWUI_第1张图片

private final class HwuiContext {
        ...
        HwuiContext(boolean isWideColorGamut) {
            mRenderNode = RenderNode.create("HwuiCanvas", null);
            mRenderNode.setClipToBounds(false);
            mRenderNode.setForceDarkAllowed(false);
            mIsWideColorGamut = isWideColorGamut;
            mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject,  isWideColorGamut);
        }
        Canvas lockCanvas(int width, int height) {
            mCanvas = mRenderNode.beginRecording(width, height);
            return mCanvas;
        }
        void unlockAndPost(Canvas canvas) {
           ...
            mRenderNode.endRecording();
            mCanvas = null;
            nHwuiDraw(mHwuiRenderer);
        }

        void updateSurface() {
            nHwuiSetSurface(mHwuiRenderer, mNativeObject);
        }
...
    }
  • step2:
    HwuiContext在构造函数中调用 RenderNode.create和nHwuiCreate方法

RenderNode.create流程

用以录制绘图操纵的批处理,当绘制的时候,可以store和apply
其实RenderNode就对应前面我们所说的ViewGroup,有一个RootView,同样也有一个RootNode
在RenderNode.create时候new一个RenderNode,进而调用到nCreate,然后创建一个native层的RenderNode


* frameworks/base/graphics/java/android/graphics/RenderNode.java
private RenderNode(String name, AnimationHost animationHost) {
        mNativeRenderNode = nCreate(name);
        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode);
        mAnimationHost = animationHost;
}
public static RenderNode create(String name, @Nullable AnimationHost animationHost) {
        return new RenderNode(name, animationHost);
}
* frameworks/base/core/jni/android_view_RenderNode.cpp
static jlong android_view_RenderNode_create(JNIEnv* env, jobject, jstring name) {
    RenderNode* renderNode = new RenderNode();
    ...
    return reinterpret_cast<jlong>(renderNode);
}

创建nHwuiCreate流程: nHwuiCreate实现在android_view_Surface中的hwui::create,创建了一个RenderProxy,nHwuiCreate返回的是一个RenderProxy实例

RenderProxy

  • RenderProxy是一个代理者,严格的单线程。所有的方法都必须在自己的线程中调用
  • RenderThread,渲染线程,是一个单例,也就是说,一个进程中只有一个,所有的绘制操纵都必须在这个线程中完成。应用端很多操纵,都以RenderTask的形式post到RenderThread线程中完成
  • CanvasContext,上下文,由于OpenGL是单线程的,所以,我们给到GPU的绘图命令都封装在各自的上下文中。这个和上层的HwuiRenderer是对应的
  • DrawFrameTask,比较特殊的一个RenderTask。可重复使用的绘制Task,在Surface的draw中调用syncAndDrawFrame
  • nHwuiCreate中在RenderProxy创建完成后,调用proxy->setSurface向RenderThread的WorkQueue队列中post一个东西,在process中执行CanvasContext::setSurface
* frameworks/base/core/jni/android_view_Surface.cpp
static jlong create(JNIEnv* env, jclass clazz, jlong rootNodePtr, jlong surfacePtr,  jboolean isWideColorGamut) {
    RenderNode* rootNode = reinterpret_cast<RenderNode*>(rootNodePtr);
    sp<Surface> surface(reinterpret_cast<Surface*>(surfacePtr));
    ContextFactory factory;
    RenderProxy* proxy = new RenderProxy(false, rootNode, &factory);
	...
    proxy->setSurface(surface);
    ...
    return (jlong) proxy;
}

* frameworks/base/libs/hwui/renderthread/RenderProxy.cpp
RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) : mRenderThread(RenderThread::getInstance()), mContext(nullptr) {
    mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* {
        return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory);
    });
    mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode);
}
void RenderProxy::setSurface(const sp<Surface>& surface) {
    mRenderThread.queue().post(
            [this, surf = surface]() mutable { mContext->setSurface(std::move(surf)); });
}

RenderThread

  • RenderThread构造函数中调用PREVENT_COPY_AND_ASSIGN的目的是阻止拷贝构造函数和=重载
  • 继承ThreadBase,ThreadBase继承Android的基本类Thread,在构造RenderThread时,调用start(“RenderThread”)就启动了RenderThread线程
  • RenderThread起来后,就会执行RenderThread的threadLoop,threadLoop中执行while循环,不停处理请求。如果没有任务时,调用waitForWork等待
  • RenderThread收到新消息后调用processQueue,然后通过threadLoop::processQueue调用到mQueue.process,从而进入到WorkQueue::process,最后调用到CanvasContext->setSurface

ThreadBase

  • 继承Thread,包含成员mLooper、mQueue
  • mQueue的实例化,C++的新特性。其实就是构造一个WorkQueue,第一个参数是一个函数,函数体执行的时候调用mLooper->wake()唤醒mLooper,线程开始工作
* frameworks/base/libs/hwui/renderthread/RenderThread.h
class RenderThread : private ThreadBase {
    PREVENT_COPY_AND_ASSIGN(RenderThread);
}
bool RenderThread::threadLoop() {
    setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
    Looper::setForThread(mLooper);
    if (gOnStartHook) {
        gOnStartHook("RenderThread");
    }
    initThreadLocals();
    while (true) {
        waitForWork();
        processQueue();
        ...
    }
}

* frameworks/base/libs/hwui/thread/ThreadBase.h
ThreadBase() : Thread(false)
            , mLooper(new Looper(false))
            , mQueue([this]() { mLooper->wake(); }, mLock) {}

WorkQueue

  • 包含一个结构体WorkItem ,其实就是前面RenderProxy::setSurface时候的匿名函数体mContext->setSurface
  • post方法调用到WorkQueue::postAt方法中创建一个WorkItem 并调用WorkQueue::enqueue加入到消息队列,最后如果需要唤醒,就通过mWakeFunc函数
  • mWakeFunc是ThreadBase中构建WorkQueue时,传下来的无名函数
* frameworks/base/libs/hwui/thread/WorkQueue.h
WorkQueue(std::function<void()>&& wakeFunc, std::mutex& lock)
            : mWakeFunc(move(wakeFunc)), mLock(lock) {}
 void enqueue(WorkItem&& item) {
        bool needsWakeup;
        {
            std::unique_lock _lock{mLock};
            auto insertAt = std::find_if(std::begin(mWorkQueue), std::end(mWorkQueue),
                    [time = item.runAt](WorkItem & item) { return item.runAt > time; });
            needsWakeup = std::begin(mWorkQueue) == insertAt;
            mWorkQueue.emplace(insertAt, std::move(item));
        }
        if (needsWakeup) {
            mWakeFunc();
        }
    }

CanvasContext渲染的上下文

  • 渲染Pipeline有几种类型,Pipeline由IRenderPipeline描述。创建CanvasContext时,会根据pipeline的类型,创建对应的Pipeline
  • IRenderPipeline是统一的接口。默认的类型是OpenGLPipeline,用的是OpenGL实现。这可以可通过属性debug.hwui.renderer来设置
  • SkiaOpenGLPipeline和SkiaVulkanPipeline,两者都用到skia进行Ops的渲染,也就是说,Ops的录制是用skia来完成的。后面的显示才用到OpenGL或Vulkan

SurfaceFlinger学习笔记(五)之HWUI_第2张图片

* frameworks/base/libs/hwui/Properties.h
enum class RenderPipelineType { SkiaGL, SkiaVulkan, NotInitialized = 128 };

* frameworks/base/libs/hwui/renderthread/CanvasContext.cpp
CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,RenderNode* rootRenderNode, IContextFactory* contextFactory) {
    auto renderType = Properties::getRenderPipelineType();
    switch (renderType) {
        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;
}
void CanvasContext::setSurface(sp<Surface>&& surface) {
	if (surface) {
        mNativeSurface = new ReliableSurface{std::move(surface)};
        mNativeSurface->setDequeueTimeout(500_ms);
    } else {
        mNativeSurface = nullptr;
    }
    ...
	bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode, mRenderAheadCapacity);
}

* frameworks/base/libs/hwui/Properties.cpp
RenderPipelineType Properties::peekRenderPipelineType() {
    ...
    property_get(PROPERTY_RENDERER, prop, useVulkan ? "skiavk" : "skiagl");
    if (!strcmp(prop, "skiavk")) {
        return RenderPipelineType::SkiaVulkan;
    }
    return RenderPipelineType::SkiaGL;
}

step3:

HwuiContext ::lockCanvas中调用mRenderNode.beginRecording->RecordingCanvas.obtain构造RecordingCanvas,RecordingCanvas构造时候主要是调用jni方法nCreateDisplayListCanvas

  • RecordingCanvas继承DisplayListCanvas,而DisplayListCanvas继承BaseRecordingCanvas ,BaseRecordingCanvas 继承Canvas
  • nCreateDisplayListCanvas实现在android_view_DisplayListCanvas中,调用Canvas::create_recording_canva
  • hwui的Canvas里面封装了create_recording_canvas、 drawText、drawDoubleRoundRectXY等,其中create_recording_canvas调用new uirenderer::skiapipeline::SkiaRecordingCanvas(renderNode, width, height)
* frameworks/base/graphics/java/android/graphics/RecordingCanvas.java
 protected RecordingCanvas(@NonNull RenderNode node, int width, int height) {
        super(nCreateDisplayListCanvas(node.mNativeRenderNode, width, height));
        mDensity = 0; // disable bitmap density scaling
}
static RecordingCanvas obtain(@NonNull RenderNode node, int width, int height) {
        if (node == null) throw new IllegalArgumentException("node cannot be null");
        RecordingCanvas canvas = sPool.acquire();
        if (canvas == null) {
            canvas = new RecordingCanvas(node, width, height);
        } else {
            nResetDisplayListCanvas(canvas.mNativeCanvasWrapper, node.mNativeRenderNode, width, height);
        }
        canvas.mNode = node;
        canvas.mWidth = width;
        canvas.mHeight = height;
        return canvas;
    }

* frameworks/base/core/jni/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));
}

frameworks/base/libs/hwui/hwui/Canvas.cpp
Canvas* Canvas::create_recording_canvas(int width, int height, uirenderer::RenderNode* renderNode) {
    return new uirenderer::skiapipeline::SkiaRecordingCanvas(renderNode, width, height);
}

SkiaRecordingCanvas

  • 继承SkiaCanvas,SkiaCanvas又继承Canvas,里面有个成员变量RecordingCanvas::mRecorder,有些绘制操作直接调用RecordingCanvas
  • 在构造时候调用SkiaRecordingCanvas::initDisplayList,这里调用RenderNode::detachAvailableList获取mAvailableDisplayList,否则创建了一个SkiaDisplayList,并调用SkiaDisplayList::attachRecorder,进而调用到RecordingCanvas::reset
  • explicit 为C++特性,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生,声明为explicit的构造函数不能在隐式转换中使用

SkiaDisplayList

  • 里面有个重要成员DisplayListData ,定义在RecordingCanvas中

SkiaCanvas

  • SkiaCanvas又继承Canvas,里面有个成员变量RecordingCanvas::mRecorder和SkCanvas::mCanvas
    mCanvas在SkiaCanvas::reset中赋值,即在SkiaRecordingCanvas::initDisplayList中把mRecorder赋值给mCanvas,则SkCanvas::mCanvas保存的是RecordingCanvas句柄

RecordingCanvas
继承SkCanvasVirtualEnforcer,SkCanvasVirtualEnforcer 为一个模块类,则继承SkNoDrawCanvas,进而继承skia::SkCanvas,这里的SkCanvas为Skia库中的

frameworks/base/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp

explicit SkiaRecordingCanvas(uirenderer::RenderNode* renderNode, int width, int height) {
        initDisplayList(renderNode, width, height);
    }
void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, int width,
                                          int height) {
    mCurrentBarrier = nullptr;
    SkASSERT(mDisplayList.get() == nullptr);
    if (renderNode) {
        mDisplayList = renderNode->detachAvailableList();
    }
    if (!mDisplayList) {
        mDisplayList.reset(new SkiaDisplayList());
    }
    mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height));
    SkiaCanvas::reset(&mRecorder);
}
* frameworks/base/libs/hwui/RenderNode.h
void attachAvailableList(skiapipeline::SkiaDisplayList* skiaDisplayList) {
        mAvailableDisplayList.reset(skiaDisplayList);
}

* frameworks/base/libs/hwui/pipeline/skia/SkiaDisplayList.h
void attachRecorder(RecordingCanvas* recorder, const SkIRect& bounds) {
        recorder->reset(&mDisplayList, bounds);
}

* frameworks/base/libs/hwui/RecordingCanvas.h
class RecordingCanvas final : public SkCanvasVirtualEnforcer<SkNoDrawCanvas> {
}

* external/skia/include/utils/SkNoDrawCanvas.h
class SK_API SkNoDrawCanvas : public SkCanvasVirtualEnforcer<SkCanvas> {
}

lockCanvas流程

canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
canvas.drawRect(x, y, x + 20.0f, y + 20.0f, paint);
  • HwuiContext ::lockCanvas中调用mRenderNode.beginRecording->RecordingCanvas.obtain构造RecordingCanvas,RecordingCanvas继承DisplayListCanvas ,DisplayListCanvas 继承BaseRecordingCanvas ,则BaseRecordingCanvas::drawColor,进而到jni的android_graphics_Canvas::drawColor
  • mNativeCanvasWrapper,就是nCreateDisplayListCanvas时,创建的native对应的Canvas,即SkiaRecordingCanvas,后续JNI中都是通过mNativeCanvasWrapper去找到对应的native的Canvas的
  • SkiaRecordingCanvas继承SkiaCanvas,则调用的SkiaCanvas::drawColor
  • SkiaCanvas::drawColor调用mCanvas的drawColor,前文说到SkCanvas::mCanvas保存的是RecordingCanvas句柄,则调用到RecordingCanvas::drawColor
  • 前文说到RecordingCanvas继承skia::SkCanvas,则这里调用到skia::SkCanvas::drawColor,进而调用到onDrawPaint,而drawRect则直接调用到onDrawRect,则进入到RecordingCanvas的onDrawPaint中
* frameworks/base/graphics/java/android/graphics/BaseRecordingCanvas.java
public final void drawColor(@ColorInt int color) {
        nDrawColor(mNativeCanvasWrapper, color, BlendMode.SRC_OVER.getXfermode().porterDuffMode);
    }
 
* frameworks/base/core/jni/android_graphics_Canvas.cpp
static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
    SkBlendMode mode = static_cast<SkBlendMode>(modeHandle);
    get_canvas(canvasHandle)->drawColor(color, mode);
}

* frameworks/base/libs/hwui/SkiaCanvas.cpp
void SkiaCanvas::drawColor(int color, SkBlendMode mode) {
    mCanvas->drawColor(color, mode);
}

* external/skia/src/core/SkCanvas.cpp
void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
    SkPaint paint;
    paint.setColor(c);
    paint.setBlendMode(mode);
    this->drawPaint(paint);
}
void SkCanvas::drawPaint(const SkPaint& paint) {
    TRACE_EVENT0("skia", TRACE_FUNC);
    this->onDrawPaint(paint);
}
void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
    TRACE_EVENT0("skia", TRACE_FUNC);
    // To avoid redundant logic in our culling code and various backends, we always sort rects
    // before passing them along.
    this->onDrawRect(r.makeSorted(), paint);
}
  • RecordingCanvas::onDrawPaint中调用到fDL->drawPaint,进而调用到DisplayListData::drawPaint
    这里的fDL为DisplayListData,在前文SkiaRecordingCanvas::initDisplayList时候调用SkiaDisplayList::attachRecorder时候调用RecordingCanvas::reset设置
  • DisplayListData::drawPaint,调用模板函数push方法,其实是new 了一个DrawPaint,并设置类型为Type::DrawPaint,保存在列表fBytes中,在draw时候,调用DisplayListData::map,进而调用到DrawPaint::draw方法
  • std::move执行到右值的无条件转换,std::forward执行到右值的有条件转换,在参数都是右值时,二者就是等价的
* frameworks/base/libs/hwui/RecordingCanvas.cpp
void RecordingCanvas::reset(DisplayListData* dl, const SkIRect& bounds) {
    this->resetCanvas(bounds.right(), bounds.bottom());
    fDL = dl;
    mClipMayBeComplex = false;
    mSaveCount = mComplexSaveCount = 0;
}
void RecordingCanvas::onDrawPaint(const SkPaint& paint) {
    fDL->drawPaint(paint);
}
void DisplayListData::drawPaint(const SkPaint& paint) {
    this->push<DrawPaint>(0, paint);
}

template <typename T, typename... Args>
void* DisplayListData::push(size_t pod, Args&&... args) {
    size_t skip = SkAlignPtr(sizeof(T) + pod);
    SkASSERT(skip < (1 << 24));
    if (fUsed + skip > fReserved) {//分配空间
        static_assert(SkIsPow2(SKLITEDL_PAGE), "This math needs updating for non-pow2.");
        // Next greater multiple of SKLITEDL_PAGE.
        fReserved = (fUsed + skip + SKLITEDL_PAGE) & ~(SKLITEDL_PAGE - 1);
        fBytes.realloc(fReserved);
    }
    SkASSERT(fUsed + skip <= fReserved);
    auto op = (T*)(fBytes.get() + fUsed);//op指向fBytes的末尾
    fUsed += skip;//fUsed增加对象的空间
    //创建T,并传入参数,移动空间,这里new (op)T,是在op指向的位置上构造T
    new (op) T{std::forward<Args>(args)...};
    op->type = (uint32_t)T::kType;
    op->skip = skip;
    return op + 1;
}

unlockCanvasAndPost

Surface::unlockCanvasAndPost调用HwuiContext::unlockAndPost开始

先调用RenderNode::endRecording

  • endRecording先通过RecordingCanvas::finishRecording调用native方法nFinishRecording,然后在jni中调用到SkiaRecordingCanvas::finishRecording,然后SkiaRecordingCanvas通过mRecorder调用到RecordingCanvas::restoreToCount这里其实调用的是external下skia库中的SkCanvas::restoreToCount,然后调用到SkCanvas::restore,进而调用到RecordingCanvas::willRestore
    SkiaRecordingCanvas调用restoreToCount后,调用DisplayList::release返回DisplayList
  • 然后调用RenderNode::nSetDisplayList,然后调用到HWUI中的RenderNode.cpp的setStagingDisplayList
* frameworks/base/core/java/android/view/Surface.java
public void unlockCanvasAndPost(Canvas canvas) {
	...
            if (mHwuiContext != null) {
                mHwuiContext.unlockAndPost(canvas);
            } else {
                unlockSwCanvasAndPost(canvas);
            }
}

void unlockAndPost(Canvas canvas) {
            mRenderNode.endRecording();
            mCanvas = null;
            nHwuiDraw(mHwuiRenderer);
}

* frameworks/base/graphics/java/android/graphics/RenderNode.java
 public void endRecording() {
        RecordingCanvas canvas = mCurrentRecordingCanvas;
        mCurrentRecordingCanvas = null;
        long displayList = canvas.finishRecording();
        nSetDisplayList(mNativeRenderNode, displayList);
        canvas.recycle();
    }
* frameworks/base/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() {
    // close any existing chunks if necessary
    insertReorderBarrier(false);
    mRecorder.restoreToCount(1);
    return mDisplayList.release();
}
* frameworks/base/libs/hwui/RecordingCanvas.cpp
void RecordingCanvas::willRestore() {
    mSaveCount--;
    if (mSaveCount < mComplexSaveCount) {
        mClipMayBeComplex = false;
        mComplexSaveCount = 0;
    }
    fDL->restore();
}
* frameworks/base/libs/hwui/RenderNode.cpp
void RenderNode::setStagingDisplayList(DisplayList* displayList) {
    mValid = (displayList != nullptr);
    mNeedsDisplayListSync = true;
    delete mStagingDisplayList;
    mStagingDisplayList = displayList;
}

HwuiContext::unlockAndPost中然后调用jni方法nHwuiDraw,进而进入到android_view_Surface的draw方法,然后调用RenderProxy::syncAndDrawFrame,然后调用到DrawFrameTask::drawFrame,这里主要是通过调用DrawFrameTask::postAndWait

  • drawFrame,也就通过RenderThread,post一个WorkItem到RenderThread的队列里面,在RenderThread线程中执行的,RenderThread处理Queue时,执行的确是这里的run函数
  • DrawFrameTask::run先调用syncFrameState,同步一下Frame的状态,再通过CanvasContext的draw方法去绘制,主要的流程就到CanvasContext,在create时候SkiaOpenGLPipeline和SkiaVulkanPipeline
* frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp
void DrawFrameTask::postAndWait() {
    AutoMutex _lock(mLock);
    mRenderThread->queue().post([this]() { run(); });
    mSignal.wait(mLock);
}

void DrawFrameTask::run() {
	...
	TreeInfo info(TreeInfo::MODE_FULL, *mContext);
	canUnblockUiThread = syncFrameState(info);
	...
	context->draw();
	...
}

DrawFrameTask::syncFrameState

  • makeCurrent,这个从早期的版本就有,早期只有Opengl pipeline时,Opengl只支持单线程。我们首先要通过makeCurrent,告诉GPU处理当前的上下文(context)。
  • unpinImages,hwui为了提高速度,对各种object都做了cache,这里的unpin,就是让cache去做unpin,以前的都不要了。
  • setContentDrawBounds,设置绘制的区域大小
  • prepareTree,前面我们也说过,Android View是树型结构的,这就是在绘制之前,去准备这些Tree节点的绘图操作Ops。这个过程也是非常的复杂
* frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp
bool DrawFrameTask::syncFrameState(TreeInfo& info) {
    ...
    bool canDraw = mContext->makeCurrent();
    mContext->unpinImages();
	...
    mContext->setContentDrawBounds(mContentDrawBounds);
    mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode);
	...
}

SurfaceFlinger学习笔记(五)之HWUI_第3张图片

前面其中就两个主要的流程:CanvasContext::PrepareTree和CanvasContext::Draw
CanvasContext::prepareTree

  • RenderNode::prepareTree,Context可能会有多个RenderNode,每个RenderNode都进行Prepare
    在RenderNode进行Prepare时,先对TreeInfo进行封,MarkAndSweepRemoved,主要是对可能的Node进行标记删除,能从tree上删除的就添加到mMarked中,在析构函数中,再对mMarked的mode进行删除
void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target) {
    ...
    mAnimationContext->startFrame(info.mode);
    mRenderPipeline->onPrepareTree();
    //Context可能会有多个RenderNode,每个RenderNode都进行Prepare
    for (const sp<RenderNode>& node : mRenderNodes) {
        //只有Primary的node是 FULL,其他都是实时,这里为MODE_FULL
        info.mode = (node.get() == target ? TreeInfo::MODE_FULL : TreeInfo::MODE_RT_ONLY);
        node->prepareTree(info);
        GL_CHECKPOINT(MODERATE);
    }
   ...
    mIsDirty = true;
	// 如果,窗口已经没有Native Surface,这一帧就丢掉。
    if (CC_UNLIKELY(!hasSurface())) {
        mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
        info.out.canDrawThisFrame = false;
        return;
    }
    ...
}
* frameworks/base/libs/hwui/RenderNode.cpp
void RenderNode::prepareTree(TreeInfo& info) {
    MarkAndSweepRemoved observer(&info);
    const int before = info.disableForceDark;
    prepareTreeImpl(observer, info, false);
}
* frameworks/base/libs/hwui/RenderNode.h
//能从tree上删除的就添加到mMarked中,在析构函数中,再对mMarked的mode进行删除
Class MarkAndSweepRemoved : public TreeObserver {
    PREVENT_COPY_AND_ASSIGN(MarkAndSweepRemoved);
public:
    explicit MarkAndSweepRemoved(TreeInfo* info) : mTreeInfo(info) {}
    //emplace_back在容器尾部添加一个元素,这个元素原地构造,不需要触发拷贝构造和转移构造。而且调用形式更加简洁,直接根据参数初始化临时对象的成员
    void onMaybeRemovedFromTree(RenderNode* node) override { mMarked.emplace_back(node); }
   ...
private:
    FatVector<sp<RenderNode>, 10> mMarked;
    TreeInfo* mTreeInfo;
};

RenderNode::prepareTreeImpl是RenderNode真正进行Prepare的地方,DisplayList的数据更新到了Context的mLayerUpdateQueue中

  • damageAccumulator是从CanvasContext中传过来的,是CanvasContext的成员,damage的累乘器。主要是用来标记,屏幕的那些区域被破坏了,需要重新绘制,所有的RenderNode累加起来,就是总的
    damage累加器中,每一个元素由DirtyStack描述,分两种类型:TransformMatrix4和TransformRenderNode。采用一个双向链表mHead进行管理
  • pushStagingPropertiesChanges,property是对RenderNode的描述,也就是对View的描述,比如大小,位置等。有两个状态,正在使用的syncProperties和待处理的mStagingProperties。syncProperties时,将mStagingProperties赋值给syncProperties。这里,很多状态都是这样同步的
  • pushStagingDisplayListChanges,和前面的Property一样的流程,只是这里是syncDisplayList。这样,前面录制好Ops,就通过mStagingDisplayList传给mDisplayList,绘制的Ops都放在mDisplayList中,这边会去递归的调用每个RenderNode的prepareTreeImpl
  • pushLayerUpdate,将要更新的RenderNode都加到TreeInfo的layerUpdateQueue中,还有其对应的damage大小
  • 累加器的popTransform,就是将该Node的DirtyStack生效
void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer) {
    ...
    info.damageAccumulator->pushTransform(this);
    if (info.mode == TreeInfo::MODE_FULL) {
        pushStagingPropertiesChanges(info);
    }

    ...
    prepareLayer(info, animatorDirtyMask);
    if (info.mode == TreeInfo::MODE_FULL) {
        pushStagingDisplayListChanges(observer, info);
    }
    if (mDisplayList) {
        info.out.hasFunctors |= mDisplayList->hasFunctor();
        bool isDirty = mDisplayList->prepareListAndChildren(
                observer, info, childFunctorsNeedLayer,
                [](RenderNode* child, TreeObserver& observer, TreeInfo& info,
                   bool functorsNeedLayer) {
                    child->prepareTreeImpl(observer, info, functorsNeedLayer);
                });
        if (isDirty) {
            damageSelf(info);
        }
    }
    pushLayerUpdate(info);

    if (!mProperties.getAllowForceDark()) {
        info.disableForceDark--;
    }
    info.damageAccumulator->popTransform();
}
* frameworks/base/libs/hwui/DamageAccumulator.cpp
void DamageAccumulator::pushCommon() {
    if (!mHead->next) {
        DirtyStack* nextFrame = mAllocator.create_trivial<DirtyStack>();
        nextFrame->next = nullptr;
        nextFrame->prev = mHead;
        mHead->next = nextFrame;
    }
    mHead = mHead->next;
    mHead->pendingDirty.setEmpty();
}

void DamageAccumulator::pushTransform(const RenderNode* transform) {
    pushCommon();
    mHead->type = TransformRenderNode;
    mHead->renderNode = transform;
}

CanvasContext::Draw

CanvasContext Prepare完后,绘制一帧的数据就准备好了。绘制是在各自的pipeline中进行的
这里为SkiaOpenGLPipeline

  • CanvasContext::draw先调用SkiaOpenGLPipeline::getFrame,进而调用mEglManager.beginFrame
    Frame是描述一帧数据信息的,主要是宽,高,ufferAge,和Surface这几个属性。绘制开始时,由EglManager根据Surface的属性构建
  • 然后调用SkiaOpenGLPipeline::draw
void CanvasContext::draw() {
	...
	Frame frame = mRenderPipeline->getFrame();
	...
	bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,  mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes, &(profiler()));
    ...                                  
}

* frameworks/base/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
class SkiaOpenGLPipeline : public SkiaPipeline, public IGpuContextCallback {
}

* frameworks/base/libs/hwui/renderthread/EglManager.cpp
Frame EglManager::beginFrame(EGLSurface surface) {
    LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE, "Tried to beginFrame on EGL_NO_SURFACE!");
    makeCurrent(surface);
    Frame frame;
    frame.mSurface = surface;
    eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, &frame.mWidth);
    eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, &frame.mHeight);
    frame.mBufferAge = queryBufferAge(surface);
    eglBeginFrame(mEglDisplay, surface);
    return frame;
}

SkiaOpenGLPipeline::draw

  • 调用EglManager.damageFrame主要是部分更新参数的设置,前面我们也damage的区域就是前面Prepare时累加器累加出来的
  • 通过FrameInfoVisualizer::draw调用SkiaProfileRenderer::drawRect,中保存SkCanvas::mCanvas成,draw时候调用SkCanvas对应的方法,进而调用到RecordingCanvas::onDrawRect
* frameworks/base/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
                              const LightGeometry& lightGeometry,
                              LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
                              bool opaque, const LightInfo& lightInfo,
                              const std::vector<sp<RenderNode>>& renderNodes,
                              FrameInfoVisualizer* profiler) {
    mEglManager.damageFrame(frame, dirty);
	...
    SkiaPipeline::updateLighting(lightGeometry, lightInfo);
    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,  SkMatrix::I());
    layerUpdateQueue->clear();

    if (CC_UNLIKELY(Properties::showDirtyRegions ||
                    ProfileType::None != Properties::getProfileType())) {
        SkCanvas* profileCanvas = surface->getCanvas();
        SkiaProfileRenderer profileRenderer(profileCanvas);
        profiler->draw(profileRenderer);
        profileCanvas->flush();
    }
	...
    return true;
}

* frameworks/base/libs/hwui/pipeline/skia/SkiaProfileRenderer.cpp
void SkiaProfileRenderer::drawRect(float left, float top, float right, float bottom,
                                   const SkPaint& paint) {
    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
    mCanvas->drawRect(rect, paint);
}

* external/skia/src/core/SkCanvas.cpp
void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
    ...
    this->onDrawRect(r.makeSorted(), paint);
}

你可能感兴趣的:(技术总结,SurfaceFlinger)